root/chrome/browser/sync/profile_sync_service_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACTION
  2. first_setup_in_progress_
  3. OnStateChanged
  4. first_setup_in_progress
  5. Initialize
  6. ACTION
  7. ACTION
  8. SetUp
  9. TearDown
  10. IssueTestTokens
  11. CreateService
  12. ShutdownAndDeleteService
  13. Initialize
  14. ExpectDataTypeManagerCreation
  15. ExpectSyncBackendHostCreation
  16. PrepareDelayedInitSyncBackendHost
  17. profile
  18. service
  19. components_factory
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F
  29. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/values.h"
#include "chrome/browser/invalidation/fake_invalidation_service.h"
#include "chrome/browser/invalidation/invalidation_service_factory.h"
#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/glue/data_type_manager_impl.h"
#include "chrome/browser/sync/glue/sync_backend_host_mock.h"
#include "chrome/browser/sync/managed_user_signin_manager_wrapper.h"
#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chrome/test/base/testing_profile.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/sync_driver/pref_names.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/gaia/gaia_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace browser_sync {

namespace {

ACTION(ReturnNewDataTypeManager) {
  return new browser_sync::DataTypeManagerImpl(arg0,
                                               arg1,
                                               arg2,
                                               arg3,
                                               arg4,
                                               arg5);
}

using testing::StrictMock;
using testing::_;

class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver {
 public:
  explicit TestProfileSyncServiceObserver(ProfileSyncService* service)
      : service_(service), first_setup_in_progress_(false) {}
  virtual void OnStateChanged() OVERRIDE {
    first_setup_in_progress_ = service_->FirstSetupInProgress();
  }
  bool first_setup_in_progress() const { return first_setup_in_progress_; }
 private:
  ProfileSyncService* service_;
  bool first_setup_in_progress_;
};

// A variant of the SyncBackendHostMock that won't automatically
// call back when asked to initialized.  Allows us to test things
// that could happen while backend init is in progress.
class SyncBackendHostNoReturn : public SyncBackendHostMock {
  virtual void 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) OVERRIDE {}
};

ACTION(ReturnNewSyncBackendHostMock) {
  return new browser_sync::SyncBackendHostMock();
}

ACTION(ReturnNewSyncBackendHostNoReturn) {
  return new browser_sync::SyncBackendHostNoReturn();
}

// A test harness that uses a real ProfileSyncService and in most cases a
// MockSyncBackendHost.
//
// This is useful if we want to test the ProfileSyncService and don't care about
// testing the SyncBackendHost.
class ProfileSyncServiceTest : public ::testing::Test {
 protected:
  ProfileSyncServiceTest()
      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
  virtual ~ProfileSyncServiceTest() {}

  virtual void SetUp() OVERRIDE {
    TestingProfile::Builder builder;

    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
                              BuildAutoIssuingFakeProfileOAuth2TokenService);
    invalidation::InvalidationServiceFactory::GetInstance()->
        RegisterTestingFactory(invalidation::FakeInvalidationService::Build);

    profile_ = builder.Build().Pass();
  }

  virtual void TearDown() OVERRIDE {
    // Kill the service before the profile.
    if (service_)
      service_->Shutdown();

    service_.reset();
    profile_.reset();
  }

  void IssueTestTokens() {
    ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
        ->UpdateCredentials("test", "oauth2_login_token");
  }

  void CreateService(ProfileSyncServiceStartBehavior behavior) {
    SigninManagerBase* signin =
        SigninManagerFactory::GetForProfile(profile_.get());
    signin->SetAuthenticatedUsername("test");
    ProfileOAuth2TokenService* oauth2_token_service =
        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
    components_factory_ = new StrictMock<ProfileSyncComponentsFactoryMock>();
    service_.reset(new ProfileSyncService(
        components_factory_,
        profile_.get(),
        new ManagedUserSigninManagerWrapper(profile_.get(), signin),
        oauth2_token_service,
        behavior));
  }

  void ShutdownAndDeleteService() {
    if (service_)
      service_->Shutdown();
    service_.reset();
  }

  void Initialize() {
    service_->Initialize();
  }

  void ExpectDataTypeManagerCreation() {
    EXPECT_CALL(*components_factory_, CreateDataTypeManager(_, _, _, _, _, _)).
        WillOnce(ReturnNewDataTypeManager());
  }

  void ExpectSyncBackendHostCreation() {
    EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _)).
        WillOnce(ReturnNewSyncBackendHostMock());
  }

  void PrepareDelayedInitSyncBackendHost() {
    EXPECT_CALL(*components_factory_, CreateSyncBackendHost(_, _, _)).
        WillOnce(ReturnNewSyncBackendHostNoReturn());
  }

  TestingProfile* profile() {
    return profile_.get();
  }

  ProfileSyncService* service() {
    return service_.get();
  }

  ProfileSyncComponentsFactoryMock* components_factory() {
    return components_factory_;
  }

 private:
  scoped_ptr<TestingProfile> profile_;
  scoped_ptr<ProfileSyncService> service_;

  // Pointer to the components factory.  Not owned.  May be null.
  ProfileSyncComponentsFactoryMock* components_factory_;

  content::TestBrowserThreadBundle thread_bundle_;
};

// Verify that the server URLs are sane.
TEST_F(ProfileSyncServiceTest, InitialState) {
  CreateService(browser_sync::AUTO_START);
  Initialize();
  const std::string& url = service()->sync_service_url().spec();
  EXPECT_TRUE(url == ProfileSyncService::kSyncServerUrl ||
              url == ProfileSyncService::kDevServerUrl);
}

// Verify a successful initialization.
TEST_F(ProfileSyncServiceTest, SuccessfulInitialization) {
  profile()->GetTestingPrefService()->SetManagedPref(
      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(false));
  IssueTestTokens();
  CreateService(browser_sync::AUTO_START);
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  Initialize();
  EXPECT_FALSE(service()->IsManaged());
  EXPECT_TRUE(service()->sync_initialized());
}


// Verify that the SetSetupInProgress function call updates state
// and notifies observers.
TEST_F(ProfileSyncServiceTest, SetupInProgress) {
  CreateService(browser_sync::AUTO_START);
  Initialize();

  TestProfileSyncServiceObserver observer(service());
  service()->AddObserver(&observer);

  service()->SetSetupInProgress(true);
  EXPECT_TRUE(observer.first_setup_in_progress());
  service()->SetSetupInProgress(false);
  EXPECT_FALSE(observer.first_setup_in_progress());

  service()->RemoveObserver(&observer);
}

// Verify that disable by enterprise policy works.
TEST_F(ProfileSyncServiceTest, DisabledByPolicyBeforeInit) {
  profile()->GetTestingPrefService()->SetManagedPref(
      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true));
  IssueTestTokens();
  CreateService(browser_sync::AUTO_START);
  Initialize();
  EXPECT_TRUE(service()->IsManaged());
  EXPECT_FALSE(service()->sync_initialized());
}

// Verify that disable by enterprise policy works even after the backend has
// been initialized.
TEST_F(ProfileSyncServiceTest, DisabledByPolicyAfterInit) {
  IssueTestTokens();
  CreateService(browser_sync::AUTO_START);
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  Initialize();

  EXPECT_FALSE(service()->IsManaged());
  EXPECT_TRUE(service()->sync_initialized());

  profile()->GetTestingPrefService()->SetManagedPref(
      sync_driver::prefs::kSyncManaged, base::Value::CreateBooleanValue(true));

  EXPECT_TRUE(service()->IsManaged());
  EXPECT_FALSE(service()->sync_initialized());
}

// Exercies the ProfileSyncService's code paths related to getting shut down
// before the backend initialize call returns.
TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
  CreateService(browser_sync::AUTO_START);
  PrepareDelayedInitSyncBackendHost();

  IssueTestTokens();
  Initialize();
  EXPECT_FALSE(service()->sync_initialized());

  ShutdownAndDeleteService();
}

// Test StopAndSuppress() before we've initialized the backend.
TEST_F(ProfileSyncServiceTest, EarlyStopAndSuppress) {
  CreateService(browser_sync::AUTO_START);
  IssueTestTokens();

  service()->StopAndSuppress();
  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));

  // Because of supression, this should fail.
  Initialize();
  EXPECT_FALSE(service()->sync_initialized());

  // Remove suppression.  This should be enough to allow init to happen.
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  service()->UnsuppressAndStart();
  EXPECT_TRUE(service()->sync_initialized());
  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));
}

// Test StopAndSuppress() after we've initialized the backend.
TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
  CreateService(browser_sync::AUTO_START);
  IssueTestTokens();
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  Initialize();

  EXPECT_TRUE(service()->sync_initialized());
  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));

  testing::Mock::VerifyAndClearExpectations(components_factory());

  service()->StopAndSuppress();
  EXPECT_FALSE(service()->sync_initialized());
  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));

  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();

  service()->UnsuppressAndStart();
  EXPECT_TRUE(service()->sync_initialized());
  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));
}

// Certain ProfileSyncService tests don't apply to Chrome OS, for example
// things that deal with concepts like "signing out" and policy.
#if !defined (OS_CHROMEOS)

TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
  CreateService(browser_sync::AUTO_START);
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  IssueTestTokens();
  Initialize();

  EXPECT_TRUE(service()->sync_initialized());
  EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
      sync_driver::prefs::kSyncSuppressStart));

  SigninManagerFactory::GetForProfile(profile())->SignOut();
  EXPECT_FALSE(service()->sync_initialized());
}

#endif  // !defined(OS_CHROMEOS)

TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
  CreateService(browser_sync::AUTO_START);
  IssueTestTokens();
  ExpectDataTypeManagerCreation();
  ExpectSyncBackendHostCreation();
  Initialize();

  // Initial status.
  ProfileSyncService::SyncTokenStatus token_status =
      service()->GetSyncTokenStatus();
  EXPECT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
  EXPECT_TRUE(token_status.connection_status_update_time.is_null());
  EXPECT_TRUE(token_status.token_request_time.is_null());
  EXPECT_TRUE(token_status.token_receive_time.is_null());

  // Simulate an auth error.
  service()->OnConnectionStatusChange(syncer::CONNECTION_AUTH_ERROR);

  // The token request will take the form of a posted task.  Run it.
  base::RunLoop loop;
  loop.RunUntilIdle();

  token_status = service()->GetSyncTokenStatus();
  EXPECT_EQ(syncer::CONNECTION_AUTH_ERROR, token_status.connection_status);
  EXPECT_FALSE(token_status.connection_status_update_time.is_null());
  EXPECT_FALSE(token_status.token_request_time.is_null());
  EXPECT_FALSE(token_status.token_receive_time.is_null());
  EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
            token_status.last_get_token_error);
  EXPECT_TRUE(token_status.next_token_request_time.is_null());

  // Simulate successful connection.
  service()->OnConnectionStatusChange(syncer::CONNECTION_OK);
  token_status = service()->GetSyncTokenStatus();
  EXPECT_EQ(syncer::CONNECTION_OK, token_status.connection_status);
}

}  // namespace
}  // namespace browser_sync

/* [<][>][^][v][top][bottom][index][help] */