| Index: chrome/browser/sync/glue/sync_backend_host_unittest.cc
|
| diff --git a/chrome/browser/sync/glue/sync_backend_host_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
|
| index 14774a4568c71b0aca9d7a5216047e0c390b546b..075726b8c67664c9cde6f7fb7bf58c6001eb95c5 100644
|
| --- a/chrome/browser/sync/glue/sync_backend_host_unittest.cc
|
| +++ b/chrome/browser/sync/glue/sync_backend_host_unittest.cc
|
| @@ -8,6 +8,8 @@
|
|
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/message_loop.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/test/test_timeouts.h"
|
| #include "chrome/browser/sync/invalidations/invalidator_storage.h"
|
| #include "chrome/browser/sync/sync_prefs.h"
|
| #include "chrome/test/base/testing_profile.h"
|
| @@ -16,6 +18,8 @@
|
| #include "net/url_request/test_url_fetcher_factory.h"
|
| #include "sync/internal_api/public/base/model_type.h"
|
| #include "sync/internal_api/public/engine/model_safe_worker.h"
|
| +#include "sync/internal_api/public/sync_manager_factory.h"
|
| +#include "sync/internal_api/public/test/fake_sync_manager.h"
|
| #include "sync/internal_api/public/util/experiments.h"
|
| #include "sync/protocol/encryption.pb.h"
|
| #include "sync/protocol/sync_protocol_error.h"
|
| @@ -24,11 +28,27 @@
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| using content::BrowserThread;
|
| +using syncer::FakeSyncManager;
|
| +using syncer::SyncManager;
|
| +using ::testing::InvokeWithoutArgs;
|
| +using ::testing::_;
|
|
|
| namespace browser_sync {
|
|
|
| namespace {
|
|
|
| +ACTION_P(Signal, event) {
|
| + event->Signal();
|
| +}
|
| +
|
| +void SignalEvent(base::WaitableEvent* event) {
|
| + event->Signal();
|
| +}
|
| +
|
| +static void QuitMessageLoop() {
|
| + MessageLoop::current()->Quit();
|
| +}
|
| +
|
| class MockSyncFrontend : public SyncFrontend {
|
| public:
|
| virtual ~MockSyncFrontend() {}
|
| @@ -56,21 +76,103 @@ class MockSyncFrontend : public SyncFrontend {
|
| MOCK_METHOD0(OnSyncConfigureRetry, void());
|
| };
|
|
|
| -} // namespace
|
| +class FakeSyncManagerFactory : public syncer::SyncManagerFactory {
|
| + public:
|
| + FakeSyncManagerFactory() : manager_(NULL) {}
|
| + virtual ~FakeSyncManagerFactory() {}
|
| +
|
| + // Takes ownership of |manager|.
|
| + void SetSyncManager(FakeSyncManager* manager) {
|
| + DCHECK(!manager_.get());
|
| + manager_.reset(manager);
|
| + }
|
| +
|
| + // Passes ownership of |manager_|.
|
| + // SyncManagerFactory implementation.
|
| + virtual scoped_ptr<SyncManager> CreateSyncManager(std::string name) OVERRIDE {
|
| + DCHECK(manager_.get());
|
| + return manager_.Pass();
|
| + }
|
| +
|
| + private:
|
| + scoped_ptr<SyncManager> manager_;
|
| +};
|
| +
|
| +class TestSyncBackendHost : public SyncBackendHost {
|
| + public:
|
| + TestSyncBackendHost(
|
| + const std::string& name,
|
| + Profile* profile,
|
| + const base::WeakPtr<SyncPrefs>& sync_prefs,
|
| + const base::WeakPtr<InvalidatorStorage>& invalidator_storage)
|
| + : SyncBackendHost(name, profile, sync_prefs, invalidator_storage) {
|
| + StartSyncThread();
|
| + }
|
| + virtual ~TestSyncBackendHost() {}
|
| +
|
| + void PumpSyncLoop() {
|
| + DCHECK(sync_loop());
|
| + base::WaitableEvent done(true, false);
|
| + sync_loop()->PostTask(FROM_HERE, base::Bind(&SignalEvent, &done));
|
| + done.TimedWait(base::TimeDelta::FromMilliseconds(
|
| + TestTimeouts::action_timeout_ms()));
|
| + if (!done.IsSignaled())
|
| + FAIL() << "Timed out waiting for sync loop.";
|
| + }
|
| +
|
| + void PostToSyncLoop(const base::Closure& closure) {
|
| + DCHECK(sync_loop());
|
| + sync_loop()->PostTask(FROM_HERE, closure);
|
| + }
|
| +};
|
|
|
| class SyncBackendHostTest : public testing::Test {
|
| protected:
|
| SyncBackendHostTest()
|
| : ui_thread_(BrowserThread::UI, &ui_loop_),
|
| - io_thread_(BrowserThread::IO) {}
|
| + io_thread_(BrowserThread::IO),
|
| + fake_manager_(NULL) {}
|
|
|
| virtual ~SyncBackendHostTest() {}
|
|
|
| - virtual void SetUp() {
|
| + virtual void SetUp() OVERRIDE {
|
| io_thread_.StartIOThread();
|
| + profile_.reset(new TestingProfile());
|
| + profile_->CreateRequestContext();
|
| + sync_prefs_.reset(new SyncPrefs(profile_->GetPrefs()));
|
| + invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs()));
|
| + backend_.reset(new TestSyncBackendHost(
|
| + profile_->GetDebugName(),
|
| + profile_.get(),
|
| + sync_prefs_->AsWeakPtr(),
|
| + invalidator_storage_->AsWeakPtr()));
|
| + credentials_.email = "user@example.com";
|
| + credentials_.sync_token = "sync_token";
|
| +
|
| + // The sync manager must be created on the sync loop in order to allow
|
| + // thread safety enforcement.
|
| + PostToSyncLoop(base::Bind(&SyncBackendHostTest::BuildSyncManager,
|
| + base::Unretained(this)));
|
| + PumpSyncLoop();
|
| + fake_sync_manager_factory_.SetSyncManager(fake_manager_);
|
| +
|
| + // NOTE: We can't include Passwords or Typed URLs due to the Sync Backend
|
| + // Registrar removing them if it can't find their model workers.
|
| + enabled_types_.Put(syncer::BOOKMARKS);
|
| + enabled_types_.Put(syncer::NIGORI);
|
| + enabled_types_.Put(syncer::PREFERENCES);
|
| + enabled_types_.Put(syncer::SESSIONS);
|
| + enabled_types_.Put(syncer::SEARCH_ENGINES);
|
| + enabled_types_.Put(syncer::AUTOFILL);
|
| }
|
|
|
| - virtual void TearDown() {
|
| + virtual void TearDown() OVERRIDE {
|
| + backend_->StopSyncingForShutdown();
|
| + backend_->Shutdown(false);
|
| + backend_.reset();
|
| + sync_prefs_.reset();
|
| + invalidator_storage_.reset();
|
| + profile_.reset();
|
| // Pump messages posted by the sync core thread (which may end up
|
| // posting on the IO thread).
|
| ui_loop_.RunAllPending();
|
| @@ -79,44 +181,168 @@ class SyncBackendHostTest : public testing::Test {
|
| ui_loop_.RunAllPending();
|
| }
|
|
|
| - private:
|
| + // Synchronously initializes the backend.
|
| + void InitializeBackend(syncer::ModelTypeSet enabled_types) {
|
| + EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, true)).
|
| + WillOnce(InvokeWithoutArgs(QuitMessageLoop));
|
| + backend_->Initialize(&mock_frontend_,
|
| + syncer::WeakHandle<syncer::JsEventHandler>(),
|
| + GURL(""),
|
| + enabled_types,
|
| + credentials_,
|
| + true,
|
| + &fake_sync_manager_factory_,
|
| + &handler_,
|
| + NULL);
|
| + ui_loop_.PostDelayedTask(
|
| + FROM_HERE,
|
| + ui_loop_.QuitClosure(),
|
| + base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()));
|
| + ui_loop_.Run();
|
| + }
|
| +
|
| + // Synchronously configures the backend's datatypes.
|
| + void ConfigureDataTypes(syncer::ModelTypeSet types_to_add,
|
| + syncer::ModelTypeSet types_to_remove,
|
| + BackendDataTypeConfigurer::NigoriState nigori_state) {
|
| + backend_->ConfigureDataTypes(
|
| + syncer::CONFIGURE_REASON_RECONFIGURATION,
|
| + types_to_add,
|
| + types_to_remove,
|
| + nigori_state,
|
| + base::Bind(&SyncBackendHostTest::DownloadReady,
|
| + base::Unretained(this)),
|
| + base::Bind(&SyncBackendHostTest::OnDownloadRetry,
|
| + base::Unretained(this)));
|
| + ui_loop_.PostDelayedTask(
|
| + FROM_HERE,
|
| + ui_loop_.QuitClosure(),
|
| + base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()));
|
| + ui_loop_.Run();
|
| + }
|
| +
|
| + protected:
|
| + // Note: should run on the sync thread.
|
| + void BuildSyncManager() {
|
| + DCHECK(!fake_manager_);
|
| + fake_manager_ = new FakeSyncManager("name");
|
| + }
|
| +
|
| + void PumpSyncLoop() {
|
| + backend_->PumpSyncLoop();
|
| + }
|
| +
|
| + void PostToSyncLoop(const base::Closure& closure) {
|
| + backend_->PostToSyncLoop(closure);
|
| + }
|
| +
|
| + void DownloadReady(syncer::ModelTypeSet types) {
|
| + MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + void OnDownloadRetry() {
|
| + NOTIMPLEMENTED();
|
| + }
|
| +
|
| MessageLoop ui_loop_;
|
| content::TestBrowserThread ui_thread_;
|
| content::TestBrowserThread io_thread_;
|
| + MockSyncFrontend mock_frontend_;
|
| + syncer::SyncCredentials credentials_;
|
| + syncer::TestUnrecoverableErrorHandler handler_;
|
| + scoped_ptr<TestingProfile> profile_;
|
| + scoped_ptr<SyncPrefs> sync_prefs_;
|
| + scoped_ptr<InvalidatorStorage> invalidator_storage_;
|
| + scoped_ptr<TestSyncBackendHost> backend_;
|
| + FakeSyncManagerFactory fake_sync_manager_factory_;
|
| + FakeSyncManager* fake_manager_;
|
| + syncer::ModelTypeSet enabled_types_;
|
| };
|
|
|
| +// Test basic initialization with no initial types (first time initialization).
|
| +// Only the nigori should be configured.
|
| TEST_F(SyncBackendHostTest, InitShutdown) {
|
| - std::string k_mock_url = "http://www.example.com";
|
| - net::FakeURLFetcherFactory test_factory_;
|
| - test_factory_.SetFakeResponse(k_mock_url + "/time?command=get_time", "",
|
| - false);
|
| -
|
| - TestingProfile profile;
|
| - profile.CreateRequestContext();
|
| -
|
| - SyncPrefs sync_prefs(profile.GetPrefs());
|
| - InvalidatorStorage invalidator_storage(profile.GetPrefs());
|
| - SyncBackendHost backend(profile.GetDebugName(),
|
| - &profile, sync_prefs.AsWeakPtr(),
|
| - invalidator_storage.AsWeakPtr());
|
| -
|
| - MockSyncFrontend mock_frontend;
|
| - syncer::SyncCredentials credentials;
|
| - credentials.email = "user@example.com";
|
| - credentials.sync_token = "sync_token";
|
| - syncer::TestUnrecoverableErrorHandler handler;
|
| - backend.Initialize(&mock_frontend,
|
| - syncer::WeakHandle<syncer::JsEventHandler>(),
|
| - GURL(k_mock_url),
|
| + InitializeBackend(syncer::ModelTypeSet());
|
| +
|
| + EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Has(syncer::NIGORI));
|
| + EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken(
|
| + syncer::ModelTypeSet(syncer::NIGORI)).Empty());
|
| +}
|
| +
|
| +// Test first time sync scenario. All types should be properly configured.
|
| +TEST_F(SyncBackendHostTest, FirstTimeSync) {
|
| + InitializeBackend(syncer::ModelTypeSet());
|
| + ConfigureDataTypes(enabled_types_,
|
| + syncer::ModelTypeSet(),
|
| + BackendDataTypeConfigurer::WITH_NIGORI);
|
| +
|
| + EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll(
|
| + enabled_types_));
|
| + EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_));
|
| + EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken(
|
| + enabled_types_).Empty());
|
| +}
|
| +
|
| +// Test the restart after setting up sync scenario. No enabled types should be
|
| +// downloaded or cleaned.
|
| +TEST_F(SyncBackendHostTest, Restart) {
|
| + syncer::ModelTypeSet all_but_nigori = enabled_types_;
|
| + fake_manager_->set_progress_marker_types(
|
| + enabled_types_);
|
| + fake_manager_->set_initial_sync_ended_types(enabled_types_);
|
| + InitializeBackend(enabled_types_);
|
| + ConfigureDataTypes(enabled_types_,
|
| + syncer::ModelTypeSet(),
|
| + BackendDataTypeConfigurer::WITH_NIGORI);
|
| +
|
| + EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty());
|
| + EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(),
|
| + enabled_types_).Empty());
|
| + EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_));
|
| + EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken(
|
| + enabled_types_).Empty());
|
| +}
|
| +
|
| +// Test a sync restart scenario where the nigori had never finished configuring.
|
| +// The nigori should be cleaned up, then reconfigured properly.
|
| +TEST_F(SyncBackendHostTest, PartialNigori) {
|
| + // Set sync manager behavior before passing it down. All types have progress
|
| + // markers, but nigori is missing initial sync ended.
|
| + syncer::ModelTypeSet all_but_nigori = enabled_types_;
|
| + all_but_nigori.Remove(syncer::NIGORI);
|
| + fake_manager_->set_progress_marker_types(
|
| + enabled_types_);
|
| + fake_manager_->set_initial_sync_ended_types(all_but_nigori);
|
| + InitializeBackend(enabled_types_);
|
| +
|
| + // Nigori should have been cleaned up, then configured.
|
| + EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(),
|
| + enabled_types_).
|
| + Equals(syncer::ModelTypeSet(syncer::NIGORI)));
|
| + EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals(
|
| + syncer::ModelTypeSet(syncer::NIGORI)));
|
| + EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Has(syncer::NIGORI));
|
| +}
|
| +
|
| +// Test the behavior when we lose the sync db. Although we already have types
|
| +// enabled, we should re-download all of them because we lost their data.
|
| +TEST_F(SyncBackendHostTest, LostDB) {
|
| + // Don't set any progress marker or initial_sync_ended types before
|
| + // initializing.
|
| + InitializeBackend(enabled_types_);
|
| + ConfigureDataTypes(enabled_types_,
|
| syncer::ModelTypeSet(),
|
| - credentials,
|
| - true,
|
| - &handler,
|
| - NULL);
|
| - backend.StopSyncingForShutdown();
|
| - backend.Shutdown(false);
|
| + BackendDataTypeConfigurer::WITH_NIGORI);
|
| +
|
| + EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll(
|
| + enabled_types_));
|
| + EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(),
|
| + enabled_types_).Empty());
|
| + EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_));
|
| + EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken(
|
| + enabled_types_).Empty());
|
| }
|
|
|
| -// TODO(akalin): Write more SyncBackendHost unit tests.
|
| +} // namespace
|
|
|
| } // namespace browser_sync
|
|
|