blob: 2615b248217f3554212a4d437bd4006a33ad2785 [file] [log] [blame]
// Copyright (c) 2010 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.
#ifndef CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
#define CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_
#pragma once
#include <string>
#include "base/message_loop.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/glue/data_type_manager_impl.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/test/profile_mock.h"
#include "chrome/test/sync/test_http_bridge_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
class Profile;
using browser_sync::ModelSafeRoutingInfo;
using browser_sync::sessions::ErrorCounters;
using browser_sync::sessions::SyncerStatus;
using browser_sync::sessions::SyncSessionSnapshot;
using sync_api::UserShare;
using syncable::DirectoryManager;
using syncable::ModelType;
using syncable::ScopedDirLookup;
ACTION_P(CallOnPaused, core) {
core->OnPaused();
};
ACTION_P(CallOnResumed, core) {
core->OnResumed();
}
ACTION(ReturnNewDataTypeManager) {
return new browser_sync::DataTypeManagerImpl(arg0, arg1);
}
namespace browser_sync {
// Mocks out the SyncerThread operations (Pause/Resume) since no thread is
// running in these tests, and allows tests to provide a task on construction
// to set up initial nodes to mock out an actual server initial sync
// download.
class SyncBackendHostForProfileSyncTest : public SyncBackendHost {
public:
// |initial_condition_setup_task| can be used to populate nodes before the
// OnBackendInitialized callback fires.
// |set_initial_sync_ended_on_init| determines whether we pretend that a full
// initial download has occurred and set bits for enabled data types. If
// this is false, configuring data types will require a syncer nudge.
// |synchronous_init| causes initialization to block until the syncapi has
// completed setting itself up and called us back.
SyncBackendHostForProfileSyncTest(SyncFrontend* frontend,
Profile* profile,
const FilePath& profile_path,
const DataTypeController::TypeMap& data_type_controllers,
Task* initial_condition_setup_task,
int num_expected_resumes,
int num_expected_pauses,
bool set_initial_sync_ended_on_init,
bool synchronous_init)
: browser_sync::SyncBackendHost(frontend, profile, profile_path,
data_type_controllers),
initial_condition_setup_task_(initial_condition_setup_task),
set_initial_sync_ended_on_init_(set_initial_sync_ended_on_init),
synchronous_init_(synchronous_init) {
// By default, the RequestPause and RequestResume methods will
// send the confirmation notification and return true.
ON_CALL(*this, RequestPause()).
WillByDefault(testing::DoAll(CallOnPaused(core_),
testing::Return(true)));
ON_CALL(*this, RequestResume()).
WillByDefault(testing::DoAll(CallOnResumed(core_),
testing::Return(true)));
ON_CALL(*this, RequestNudge()).WillByDefault(testing::Invoke(this,
&SyncBackendHostForProfileSyncTest::
SimulateSyncCycleCompletedInitialSyncEnded));
EXPECT_CALL(*this, RequestPause()).Times(num_expected_pauses);
EXPECT_CALL(*this, RequestResume()).Times(num_expected_resumes);
EXPECT_CALL(*this, RequestNudge()).
Times(set_initial_sync_ended_on_init ? 0 : 1);
}
MOCK_METHOD0(RequestPause, bool());
MOCK_METHOD0(RequestResume, bool());
MOCK_METHOD0(RequestNudge, void());
void SetInitialSyncEndedForEnabledTypes() {
UserShare* user_share = core_->syncapi()->GetUserShare();
DirectoryManager* dir_manager = user_share->dir_manager.get();
ScopedDirLookup dir(dir_manager, user_share->name);
if (!dir.good())
FAIL();
ModelSafeRoutingInfo enabled_types;
GetModelSafeRoutingInfo(&enabled_types);
for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
i != enabled_types.end(); ++i) {
dir->set_initial_sync_ended_for_type(i->first, true);
}
}
virtual void ConfigureDataTypes(const syncable::ModelTypeSet& types,
CancelableTask* ready_task) {
SetAutofillMigrationState(syncable::MIGRATED);
SyncBackendHost::ConfigureDataTypes(types, ready_task);
}
virtual void HandleInitializationCompletedOnFrontendLoop() {
set_syncapi_initialized(); // Need to do this asap so task below works.
// Set up any nodes the test wants around before model association.
if (initial_condition_setup_task_) {
initial_condition_setup_task_->Run();
}
// Pretend we downloaded initial updates and set initial sync ended bits
// if we were asked to.
if (set_initial_sync_ended_on_init_)
SetInitialSyncEndedForEnabledTypes();
SyncBackendHost::HandleInitializationCompletedOnFrontendLoop();
}
// Called when a nudge comes in.
void SimulateSyncCycleCompletedInitialSyncEnded() {
syncable::ModelTypeBitSet sync_ended;
ModelSafeRoutingInfo enabled_types;
GetModelSafeRoutingInfo(&enabled_types);
for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
i != enabled_types.end(); ++i) {
sync_ended.set(i->first);
}
core_->HandleSyncCycleCompletedOnFrontendLoop(new SyncSessionSnapshot(
SyncerStatus(), ErrorCounters(), 0, 0, false,
sync_ended, false, false, 0, 0, false));
}
virtual sync_api::HttpPostProviderFactory* MakeHttpBridgeFactory(
URLRequestContextGetter* getter) {
return new browser_sync::TestHttpBridgeFactory;
}
virtual void InitCore(const Core::DoInitializeOptions& options) {
std::wstring user = L"testuser";
core_loop()->PostTask(FROM_HERE,
NewRunnableMethod(core_.get(),
&SyncBackendHost::Core::DoInitializeForTest,
user,
options.http_bridge_factory,
options.delete_sync_data_folder));
// TODO(akalin): Figure out a better way to do this.
if (synchronous_init_) {
// The SyncBackend posts a task to the current loop when
// initialization completes.
MessageLoop::current()->Run();
}
}
static void SetDefaultExpectationsForWorkerCreation(ProfileMock* profile) {
EXPECT_CALL(*profile, GetPasswordStore(testing::_)).
WillOnce(testing::Return((PasswordStore*)NULL));
EXPECT_CALL(*profile, GetHistoryService(testing::_)).
WillOnce(testing::Return((HistoryService*)NULL));
}
private:
Task* initial_condition_setup_task_;
bool set_initial_sync_ended_on_init_;
bool synchronous_init_;
};
} // namespace browser_sync
class TestProfileSyncService : public ProfileSyncService {
public:
TestProfileSyncService(ProfileSyncFactory* factory,
Profile* profile,
const std::string& test_user,
bool synchronous_backend_initialization,
Task* initial_condition_setup_task)
: ProfileSyncService(factory, profile,
!test_user.empty() ?
test_user : ""),
synchronous_backend_initialization_(
synchronous_backend_initialization),
synchronous_sync_configuration_(false),
num_expected_resumes_(1),
num_expected_pauses_(1),
initial_condition_setup_task_(initial_condition_setup_task),
set_initial_sync_ended_on_init_(true) {
RegisterPreferences();
SetSyncSetupCompleted();
}
virtual ~TestProfileSyncService() { }
virtual void CreateBackend() {
backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
this, profile(),
profile()->GetPath(), data_type_controllers(),
initial_condition_setup_task_.release(),
num_expected_resumes_, num_expected_pauses_,
set_initial_sync_ended_on_init_,
synchronous_backend_initialization_));
}
virtual void OnBackendInitialized() {
ProfileSyncService::OnBackendInitialized();
// TODO(akalin): Figure out a better way to do this.
if (synchronous_backend_initialization_) {
MessageLoop::current()->Quit();
}
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
ProfileSyncService::Observe(type, source, details);
if (type == NotificationType::SYNC_CONFIGURE_DONE &&
!synchronous_sync_configuration_) {
MessageLoop::current()->Quit();
}
}
void set_num_expected_resumes(int times) {
num_expected_resumes_ = times;
}
void set_num_expected_pauses(int num) {
num_expected_pauses_ = num;
}
void dont_set_initial_sync_ended_on_init() {
set_initial_sync_ended_on_init_ = false;
}
void set_synchronous_sync_configuration() {
synchronous_sync_configuration_ = true;
}
private:
// When testing under ChromiumOS, this method must not return an empty
// value value in order for the profile sync service to start.
virtual std::string GetLsidForAuthBootstraping() {
return "foo";
}
bool synchronous_backend_initialization_;
// Set to true when a mock data type manager is being used and the configure
// step is performed synchronously.
bool synchronous_sync_configuration_;
bool set_expect_resume_expectations_;
int num_expected_resumes_;
int num_expected_pauses_;
scoped_ptr<Task> initial_condition_setup_task_;
bool set_initial_sync_ended_on_init_;
};
#endif // CHROME_BROWSER_SYNC_TEST_PROFILE_SYNC_SERVICE_H_