1// Copyright (c) 2011 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 "chrome/browser/sync/test_profile_sync_service.h"
6
7#include "chrome/browser/sync/abstract_profile_sync_service_test.h"
8#include "chrome/browser/sync/engine/syncapi.h"
9#include "chrome/browser/sync/glue/data_type_controller.h"
10#include "chrome/browser/sync/glue/sync_backend_host.h"
11#include "chrome/browser/sync/profile_sync_factory.h"
12#include "chrome/browser/sync/sessions/session_state.h"
13#include "chrome/browser/sync/syncable/directory_manager.h"
14#include "chrome/browser/sync/syncable/syncable.h"
15#include "chrome/test/sync/test_http_bridge_factory.h"
16
17using browser_sync::ModelSafeRoutingInfo;
18using browser_sync::sessions::ErrorCounters;
19using browser_sync::sessions::SyncSourceInfo;
20using browser_sync::sessions::SyncerStatus;
21using browser_sync::sessions::SyncSessionSnapshot;
22using syncable::DirectoryManager;
23using syncable::ModelType;
24using syncable::ScopedDirLookup;
25using sync_api::UserShare;
26
27namespace browser_sync {
28
29using ::testing::_;
30SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
31    Profile* profile,
32    bool set_initial_sync_ended_on_init,
33    bool synchronous_init)
34    : browser_sync::SyncBackendHost(profile),
35      synchronous_init_(synchronous_init) {
36  ON_CALL(*this, RequestNudge(_)).WillByDefault(
37      testing::Invoke(this,
38                      &SyncBackendHostForProfileSyncTest::
39                      SimulateSyncCycleCompletedInitialSyncEnded));
40  EXPECT_CALL(*this, RequestNudge(_)).Times(testing::AnyNumber());
41}
42
43SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}
44
45void SyncBackendHostForProfileSyncTest::ConfigureDataTypes(
46    const DataTypeController::TypeMap& data_type_controllers,
47    const syncable::ModelTypeSet& types,
48    CancelableTask* ready_task) {
49  SetAutofillMigrationState(syncable::MIGRATED);
50  SyncBackendHost::ConfigureDataTypes(
51      data_type_controllers, types, ready_task);
52}
53
54void SyncBackendHostForProfileSyncTest::
55    SimulateSyncCycleCompletedInitialSyncEnded(
56    const tracked_objects::Location& location) {
57  syncable::ModelTypeBitSet sync_ended;
58  ModelSafeRoutingInfo enabled_types;
59  GetModelSafeRoutingInfo(&enabled_types);
60  std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
61  for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
62       i != enabled_types.end(); ++i) {
63    sync_ended.set(i->first);
64  }
65  core_->HandleSyncCycleCompletedOnFrontendLoop(new SyncSessionSnapshot(
66      SyncerStatus(), ErrorCounters(), 0, false,
67      sync_ended, download_progress_markers, false, false, 0, 0, false,
68      SyncSourceInfo()));
69}
70
71sync_api::HttpPostProviderFactory*
72    SyncBackendHostForProfileSyncTest::MakeHttpBridgeFactory(
73        net::URLRequestContextGetter* getter) {
74  return new browser_sync::TestHttpBridgeFactory;
75}
76
77void SyncBackendHostForProfileSyncTest::InitCore(
78    const Core::DoInitializeOptions& options) {
79  std::wstring user = L"testuser@gmail.com";
80  core_loop()->PostTask(
81      FROM_HERE,
82      NewRunnableMethod(core_.get(),
83                        &SyncBackendHost::Core::DoInitializeForTest,
84                        user,
85                        options.http_bridge_factory,
86                        options.delete_sync_data_folder));
87
88  // TODO(akalin): Figure out a better way to do this.
89  if (synchronous_init_) {
90    // The SyncBackend posts a task to the current loop when
91    // initialization completes.
92    MessageLoop::current()->Run();
93  }
94}
95
96JsBackend* SyncBackendHostForProfileSyncTest::GetJsBackend() {
97  // Return a non-NULL result only when the overridden function does.
98  if (SyncBackendHost::GetJsBackend()) {
99    return this;
100  } else {
101    NOTREACHED();
102    return NULL;
103  }
104}
105
106void SyncBackendHostForProfileSyncTest::SetParentJsEventRouter(
107    JsEventRouter* router) {
108  core_->SetParentJsEventRouter(router);
109}
110
111void SyncBackendHostForProfileSyncTest::RemoveParentJsEventRouter() {
112  core_->RemoveParentJsEventRouter();
113}
114
115const JsEventRouter*
116    SyncBackendHostForProfileSyncTest::GetParentJsEventRouter() const {
117  return core_->GetParentJsEventRouter();
118}
119
120void SyncBackendHostForProfileSyncTest::ProcessMessage(
121    const std::string& name, const JsArgList& args,
122    const JsEventHandler* sender) {
123  if (name.find("delay") != name.npos) {
124    core_->RouteJsEvent(name, args, sender);
125  } else {
126    core_->RouteJsEventOnFrontendLoop(name, args, sender);
127  }
128}
129
130void SyncBackendHostForProfileSyncTest::StartConfiguration(Callback0::Type*) {
131  SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop();
132}
133
134void SyncBackendHostForProfileSyncTest::
135    SetDefaultExpectationsForWorkerCreation(ProfileMock* profile) {
136  EXPECT_CALL(*profile, GetPasswordStore(testing::_)).
137      WillOnce(testing::Return((PasswordStore*)NULL));
138}
139
140void SyncBackendHostForProfileSyncTest::SetHistoryServiceExpectations(
141    ProfileMock* profile) {
142  EXPECT_CALL(*profile, GetHistoryService(testing::_)).
143      WillOnce(testing::Return((HistoryService*)NULL));
144}
145
146}  // namespace browser_sync
147
148browser_sync::TestIdFactory* TestProfileSyncService::id_factory() {
149  return &id_factory_;
150}
151
152browser_sync::SyncBackendHostForProfileSyncTest*
153    TestProfileSyncService::GetBackendForTest() {
154  return static_cast<browser_sync::SyncBackendHostForProfileSyncTest*>(
155      ProfileSyncService::GetBackendForTest());
156}
157
158TestProfileSyncService::TestProfileSyncService(
159    ProfileSyncFactory* factory,
160                       Profile* profile,
161                       const std::string& test_user,
162                       bool synchronous_backend_initialization,
163                       Task* initial_condition_setup_task)
164    : ProfileSyncService(factory, profile, test_user),
165      synchronous_backend_initialization_(
166          synchronous_backend_initialization),
167      synchronous_sync_configuration_(false),
168      initial_condition_setup_task_(initial_condition_setup_task),
169      set_initial_sync_ended_on_init_(true) {
170  RegisterPreferences();
171  SetSyncSetupCompleted();
172}
173
174TestProfileSyncService::~TestProfileSyncService() {}
175
176void TestProfileSyncService::SetInitialSyncEndedForEnabledTypes() {
177  UserShare* user_share = GetUserShare();
178  DirectoryManager* dir_manager = user_share->dir_manager.get();
179
180  ScopedDirLookup dir(dir_manager, user_share->name);
181  if (!dir.good())
182    FAIL();
183
184  ModelSafeRoutingInfo enabled_types;
185  backend_->GetModelSafeRoutingInfo(&enabled_types);
186  for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
187       i != enabled_types.end(); ++i) {
188    dir->set_initial_sync_ended_for_type(i->first, true);
189  }
190}
191
192void TestProfileSyncService::OnBackendInitialized() {
193  // Set this so below code can access GetUserShare().
194  backend_initialized_ = true;
195
196  // Set up any nodes the test wants around before model association.
197  if (initial_condition_setup_task_) {
198    initial_condition_setup_task_->Run();
199    initial_condition_setup_task_ = NULL;
200  }
201
202  // Pretend we downloaded initial updates and set initial sync ended bits
203  // if we were asked to.
204  bool send_passphrase_required = false;
205  if (set_initial_sync_ended_on_init_) {
206    UserShare* user_share = GetUserShare();
207    DirectoryManager* dir_manager = user_share->dir_manager.get();
208
209    ScopedDirLookup dir(dir_manager, user_share->name);
210    if (!dir.good())
211      FAIL();
212
213    if (!dir->initial_sync_ended_for_type(syncable::NIGORI)) {
214      ProfileSyncServiceTestHelper::CreateRoot(
215          syncable::NIGORI, GetUserShare(),
216          id_factory());
217
218      // A side effect of adding the NIGORI mode (normally done by the syncer)
219      // is a decryption attempt, which will fail the first time.
220      send_passphrase_required = true;
221    }
222
223    SetInitialSyncEndedForEnabledTypes();
224  }
225
226  ProfileSyncService::OnBackendInitialized();
227  if (send_passphrase_required)
228    OnPassphraseRequired(true);
229
230  // TODO(akalin): Figure out a better way to do this.
231  if (synchronous_backend_initialization_) {
232    MessageLoop::current()->Quit();
233  }
234}
235
236void TestProfileSyncService::Observe(NotificationType type,
237                                     const NotificationSource& source,
238                                     const NotificationDetails& details) {
239  ProfileSyncService::Observe(type, source, details);
240  if (type == NotificationType::SYNC_CONFIGURE_DONE &&
241      !synchronous_sync_configuration_) {
242    MessageLoop::current()->Quit();
243  }
244}
245
246void TestProfileSyncService::dont_set_initial_sync_ended_on_init() {
247  set_initial_sync_ended_on_init_ = false;
248}
249void TestProfileSyncService::set_synchronous_sync_configuration() {
250  synchronous_sync_configuration_ = true;
251}
252
253void TestProfileSyncService::CreateBackend() {
254  backend_.reset(new browser_sync::SyncBackendHostForProfileSyncTest(
255      profile(),
256      set_initial_sync_ended_on_init_,
257      synchronous_backend_initialization_));
258}
259
260std::string TestProfileSyncService::GetLsidForAuthBootstraping() {
261  return "foo";
262}
263