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.
5 #include "base/basictypes.h"
6 #include "base/compiler_specific.h"
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/values.h"
11 #include "chrome/browser/invalidation/invalidation_service_factory.h"
12 #include "chrome/browser/signin/signin_manager.h"
13 #include "chrome/browser/signin/signin_manager_factory.h"
14 #include "chrome/browser/signin/token_service.h"
15 #include "chrome/browser/signin/token_service_factory.h"
16 #include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
17 #include "chrome/browser/sync/glue/data_type_controller.h"
18 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
19 #include "chrome/browser/sync/test_profile_sync_service.h"
20 #include "chrome/common/chrome_version_info.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/test/base/testing_pref_service_syncable.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "content/public/test/test_utils.h"
26 #include "google/cacheinvalidation/include/types.h"
27 #include "google_apis/gaia/gaia_constants.h"
28 #include "sync/js/js_arg_list.h"
29 #include "sync/js/js_event_details.h"
30 #include "sync/js/js_test_util.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 // TODO(akalin): Add tests here that exercise the whole
35 // ProfileSyncService/SyncBackendHost stack while mocking out as
36 // little as possible.
38 namespace browser_sync {
43 using testing::AtLeast;
44 using testing::AtMost;
46 using testing::Return;
47 using testing::StrictMock;
49 void SignalDone(base::WaitableEvent* done) {
53 class ProfileSyncServiceTest : public testing::Test {
55 ProfileSyncServiceTest()
56 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
57 content::TestBrowserThreadBundle::REAL_FILE_THREAD |
58 content::TestBrowserThreadBundle::REAL_IO_THREAD) {
61 virtual void SetUp() OVERRIDE {
62 TestingProfile::Builder builder;
63 builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
64 FakeOAuth2TokenService::BuildTokenService);
65 profile_ = builder.Build().Pass();
66 invalidation::InvalidationServiceFactory::GetInstance()->
67 SetBuildOnlyFakeInvalidatorsForTest(true);
70 virtual void TearDown() OVERRIDE {
71 // Kill the service before the profile.
78 // Pump messages posted by the sync thread (which may end up
79 // posting on the IO thread).
80 base::RunLoop().RunUntilIdle();
81 content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
82 base::RunLoop().RunUntilIdle();
85 // TODO(akalin): Refactor the StartSyncService*() functions below.
87 void StartSyncService() {
88 StartSyncServiceAndSetInitialSyncEnded(
89 true, true, false, true, syncer::STORAGE_IN_MEMORY);
92 void StartSyncServiceAndSetInitialSyncEnded(
93 bool set_initial_sync_ended,
94 bool issue_auth_token,
95 bool synchronous_sync_configuration,
96 bool sync_setup_completed,
97 syncer::StorageOption storage_option) {
101 SigninManagerBase* signin =
102 SigninManagerFactory::GetForProfile(profile_.get());
103 signin->SetAuthenticatedUsername("test");
104 ProfileOAuth2TokenService* oauth2_token_service =
105 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
106 ProfileSyncComponentsFactoryMock* factory =
107 new ProfileSyncComponentsFactoryMock();
108 service_.reset(new TestProfileSyncService(
112 oauth2_token_service,
113 ProfileSyncService::AUTO_START,
115 if (!set_initial_sync_ended)
116 service_->dont_set_initial_sync_ended_on_init();
118 if (synchronous_sync_configuration)
119 service_->set_synchronous_sync_configuration();
121 service_->set_storage_option(storage_option);
122 if (!sync_setup_completed)
123 profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, false);
125 // Register the bookmark data type.
126 ON_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
127 WillByDefault(ReturnNewDataTypeManager());
129 if (issue_auth_token)
132 service_->Initialize();
135 void WaitForBackendInitDone() {
136 for (int i = 0; i < 5; ++i) {
137 base::WaitableEvent done(false, false);
138 service_->GetBackendForTest()->GetSyncLoopForTesting()
139 ->PostTask(FROM_HERE, base::Bind(&SignalDone, &done));
141 base::RunLoop().RunUntilIdle();
142 if (service_->sync_initialized()) {
146 LOG(ERROR) << "Backend not initialized.";
149 void IssueTestTokens() {
150 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
151 ->UpdateCredentials("test", "oauth2_login_token");
154 scoped_ptr<TestProfileSyncService> service_;
155 scoped_ptr<TestingProfile> profile_;
158 content::TestBrowserThreadBundle thread_bundle_;
161 class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver {
163 explicit TestProfileSyncServiceObserver(ProfileSyncService* service)
164 : service_(service), first_setup_in_progress_(false) {}
165 virtual void OnStateChanged() OVERRIDE {
166 first_setup_in_progress_ = service_->FirstSetupInProgress();
168 bool first_setup_in_progress() const { return first_setup_in_progress_; }
170 ProfileSyncService* service_;
171 bool first_setup_in_progress_;
174 TEST_F(ProfileSyncServiceTest, InitialState) {
175 SigninManagerBase* signin =
176 SigninManagerFactory::GetForProfile(profile_.get());
177 ProfileOAuth2TokenService* oauth2_token_service =
178 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
179 service_.reset(new TestProfileSyncService(
180 new ProfileSyncComponentsFactoryMock(),
183 oauth2_token_service,
184 ProfileSyncService::MANUAL_START,
186 service_->Initialize();
188 service_->sync_service_url().spec() ==
189 ProfileSyncService::kSyncServerUrl ||
190 service_->sync_service_url().spec() ==
191 ProfileSyncService::kDevServerUrl);
194 // Tests that the sync service doesn't forget to notify observers about
196 TEST(ProfileSyncServiceTestBasic, SetupInProgress) {
197 ProfileSyncService service(
198 NULL, NULL, NULL, NULL, ProfileSyncService::MANUAL_START);
199 TestProfileSyncServiceObserver observer(&service);
200 service.AddObserver(&observer);
201 service.SetSetupInProgress(true);
202 EXPECT_TRUE(observer.first_setup_in_progress());
203 service.SetSetupInProgress(false);
204 EXPECT_FALSE(observer.first_setup_in_progress());
205 service.RemoveObserver(&observer);
208 TEST_F(ProfileSyncServiceTest, DisabledByPolicy) {
209 profile_->GetTestingPrefService()->SetManagedPref(
211 Value::CreateBooleanValue(true));
212 SigninManagerBase* signin =
213 SigninManagerFactory::GetForProfile(profile_.get());
214 ProfileOAuth2TokenService* oauth2_token_service =
215 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
216 service_.reset(new TestProfileSyncService(
217 new ProfileSyncComponentsFactoryMock(),
220 oauth2_token_service,
221 ProfileSyncService::MANUAL_START,
223 service_->Initialize();
224 EXPECT_TRUE(service_->IsManaged());
227 TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
228 SigninManagerBase* signin =
229 SigninManagerFactory::GetForProfile(profile_.get());
230 signin->SetAuthenticatedUsername("test");
231 ProfileOAuth2TokenService* oauth2_token_service =
232 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
233 ProfileSyncComponentsFactoryMock* factory =
234 new ProfileSyncComponentsFactoryMock();
235 service_.reset(new TestProfileSyncService(
239 oauth2_token_service,
240 ProfileSyncService::AUTO_START,
242 EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).Times(0);
243 EXPECT_CALL(*factory, CreateBookmarkSyncComponents(_, _)).
245 service_->RegisterDataTypeController(
246 new BookmarkDataTypeController(service_->factory(),
250 service_->Initialize();
251 service_->Shutdown();
255 TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
256 SigninManagerBase* signin =
257 SigninManagerFactory::GetForProfile(profile_.get());
258 signin->SetAuthenticatedUsername("test");
259 ProfileOAuth2TokenService* oauth2_token_service =
260 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
261 ProfileSyncComponentsFactoryMock* factory =
262 new ProfileSyncComponentsFactoryMock();
263 service_.reset(new TestProfileSyncService(
267 oauth2_token_service,
268 ProfileSyncService::AUTO_START,
270 // Register the bookmark data type.
271 EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
272 WillRepeatedly(ReturnNewDataTypeManager());
276 service_->Initialize();
277 EXPECT_TRUE(service_->sync_initialized());
278 EXPECT_TRUE(service_->GetBackendForTest() != NULL);
280 profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
282 service_->StopAndSuppress();
283 EXPECT_FALSE(service_->sync_initialized());
285 profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
287 service_->UnsuppressAndStart();
288 EXPECT_TRUE(service_->sync_initialized());
290 profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
293 // Certain ProfileSyncService tests don't apply to Chrome OS, for example
294 // things that deal with concepts like "signing out" and policy.
295 #if !defined (OS_CHROMEOS)
297 TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
298 SigninManager* signin =
299 SigninManagerFactory::GetForProfile(profile_.get());
300 signin->SetAuthenticatedUsername("test");
301 ProfileOAuth2TokenService* oauth2_token_service =
302 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
303 ProfileSyncComponentsFactoryMock* factory =
304 new ProfileSyncComponentsFactoryMock();
305 service_.reset(new TestProfileSyncService(
309 oauth2_token_service,
310 ProfileSyncService::AUTO_START,
312 // Register the bookmark data type.
313 EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
314 WillRepeatedly(ReturnNewDataTypeManager());
318 service_->Initialize();
319 EXPECT_TRUE(service_->sync_initialized());
320 EXPECT_TRUE(service_->GetBackendForTest() != NULL);
322 profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
325 EXPECT_FALSE(service_->sync_initialized());
328 #endif // !defined(OS_CHROMEOS)
330 TEST_F(ProfileSyncServiceTest, JsControllerHandlersBasic) {
332 EXPECT_TRUE(service_->sync_initialized());
333 EXPECT_TRUE(service_->GetBackendForTest() != NULL);
335 base::WeakPtr<syncer::JsController> js_controller =
336 service_->GetJsController();
337 StrictMock<syncer::MockJsEventHandler> event_handler;
338 js_controller->AddJsEventHandler(&event_handler);
339 js_controller->RemoveJsEventHandler(&event_handler);
342 TEST_F(ProfileSyncServiceTest,
343 JsControllerHandlersDelayedBackendInitialization) {
344 StartSyncServiceAndSetInitialSyncEnded(true, false, false, true,
345 syncer::STORAGE_IN_MEMORY);
347 StrictMock<syncer::MockJsEventHandler> event_handler;
348 EXPECT_CALL(event_handler, HandleJsEvent(_, _)).Times(AtLeast(1));
350 EXPECT_EQ(NULL, service_->GetBackendForTest());
351 EXPECT_FALSE(service_->sync_initialized());
353 base::WeakPtr<syncer::JsController> js_controller =
354 service_->GetJsController();
355 js_controller->AddJsEventHandler(&event_handler);
356 // Since we're doing synchronous initialization, backend should be
357 // initialized by this call.
359 EXPECT_TRUE(service_->sync_initialized());
360 js_controller->RemoveJsEventHandler(&event_handler);
363 TEST_F(ProfileSyncServiceTest, JsControllerProcessJsMessageBasic) {
365 WaitForBackendInitDone();
367 StrictMock<syncer::MockJsReplyHandler> reply_handler;
370 arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
371 syncer::JsArgList args1(&arg_list1);
372 EXPECT_CALL(reply_handler,
373 HandleJsReply("getNotificationState", HasArgs(args1)));
376 base::WeakPtr<syncer::JsController> js_controller =
377 service_->GetJsController();
378 js_controller->ProcessJsMessage("getNotificationState", args1,
379 reply_handler.AsWeakHandle());
382 // This forces the sync thread to process the message and reply.
383 base::WaitableEvent done(false, false);
384 service_->GetBackendForTest()->GetSyncLoopForTesting()
385 ->PostTask(FROM_HERE,
386 base::Bind(&SignalDone, &done));
389 // Call TearDown() to flush the message loops before the mock is destroyed.
390 // TearDown() is idempotent, so it's not a problem that it gets called by the
391 // test fixture again later.
395 TEST_F(ProfileSyncServiceTest,
396 JsControllerProcessJsMessageBasicDelayedBackendInitialization) {
397 StartSyncServiceAndSetInitialSyncEnded(true, false, false, true,
398 syncer::STORAGE_IN_MEMORY);
400 StrictMock<syncer::MockJsReplyHandler> reply_handler;
403 arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
404 syncer::JsArgList args1(&arg_list1);
405 EXPECT_CALL(reply_handler,
406 HandleJsReply("getNotificationState", HasArgs(args1)));
409 base::WeakPtr<syncer::JsController> js_controller =
410 service_->GetJsController();
411 js_controller->ProcessJsMessage("getNotificationState",
412 args1, reply_handler.AsWeakHandle());
416 WaitForBackendInitDone();
418 // This forces the sync thread to process the message and reply.
419 base::WaitableEvent done(false, false);
420 service_->GetBackendForTest()->GetSyncLoopForTesting()
421 ->PostTask(FROM_HERE,
422 base::Bind(&SignalDone, &done));
426 // Make sure that things still work if sync is not enabled, but some old sync
427 // databases are lingering in the "Sync Data" folder.
428 TEST_F(ProfileSyncServiceTest, TestStartupWithOldSyncData) {
429 const char* nonsense1 = "reginald";
430 const char* nonsense2 = "beartato";
431 const char* nonsense3 = "harrison";
432 base::FilePath temp_directory =
433 profile_->GetPath().AppendASCII("Sync Data");
434 base::FilePath sync_file1 =
435 temp_directory.AppendASCII("BookmarkSyncSettings.sqlite3");
436 base::FilePath sync_file2 = temp_directory.AppendASCII("SyncData.sqlite3");
437 base::FilePath sync_file3 = temp_directory.AppendASCII("nonsense_file");
438 ASSERT_TRUE(file_util::CreateDirectory(temp_directory));
440 file_util::WriteFile(sync_file1, nonsense1, strlen(nonsense1)));
442 file_util::WriteFile(sync_file2, nonsense2, strlen(nonsense2)));
444 file_util::WriteFile(sync_file3, nonsense3, strlen(nonsense3)));
446 StartSyncServiceAndSetInitialSyncEnded(true, false, true, false,
447 syncer::STORAGE_ON_DISK);
448 EXPECT_FALSE(service_->HasSyncSetupCompleted());
449 EXPECT_FALSE(service_->sync_initialized());
451 // Since we're doing synchronous initialization, backend should be
452 // initialized by this call.
455 // Stop the service so we can read the new Sync Data files that were
457 service_->Shutdown();
460 // This file should have been deleted when the whole directory was nuked.
461 ASSERT_FALSE(base::PathExists(sync_file3));
462 ASSERT_FALSE(base::PathExists(sync_file1));
464 // This will still exist, but the text should have changed.
465 ASSERT_TRUE(base::PathExists(sync_file2));
466 std::string file2text;
467 ASSERT_TRUE(base::ReadFileToString(sync_file2, &file2text));
468 ASSERT_NE(file2text.compare(nonsense2), 0);
471 // Simulates a scenario where a database is corrupted and it is impossible to
472 // recreate it. This test is useful mainly when it is run under valgrind. Its
473 // expectations are not very interesting.
474 TEST_F(ProfileSyncServiceTest, FailToOpenDatabase) {
475 StartSyncServiceAndSetInitialSyncEnded(false, true, true, true,
476 syncer::STORAGE_INVALID);
478 // The backend is not ready. Ensure the PSS knows this.
479 EXPECT_FALSE(service_->sync_initialized());
482 // This setup will allow the database to exist, but leave it empty. The attempt
483 // to download control types will silently fail (no downloads have any effect in
484 // these tests). The sync_backend_host will notice this and inform the profile
485 // sync service of the failure to initialize the backed.
486 TEST_F(ProfileSyncServiceTest, FailToDownloadControlTypes) {
487 StartSyncServiceAndSetInitialSyncEnded(false, true, true, true,
488 syncer::STORAGE_IN_MEMORY);
490 // The backend is not ready. Ensure the PSS knows this.
491 EXPECT_FALSE(service_->sync_initialized());
495 } // namespace browser_sync