- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / profile_sync_service_unittest.cc
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.
4
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"
33
34 // TODO(akalin): Add tests here that exercise the whole
35 // ProfileSyncService/SyncBackendHost stack while mocking out as
36 // little as possible.
37
38 namespace browser_sync {
39
40 namespace {
41
42 using testing::_;
43 using testing::AtLeast;
44 using testing::AtMost;
45 using testing::Mock;
46 using testing::Return;
47 using testing::StrictMock;
48
49 void SignalDone(base::WaitableEvent* done) {
50   done->Signal();
51 }
52
53 class ProfileSyncServiceTest : public testing::Test {
54  protected:
55   ProfileSyncServiceTest()
56       : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
57                        content::TestBrowserThreadBundle::REAL_FILE_THREAD |
58                        content::TestBrowserThreadBundle::REAL_IO_THREAD) {
59    }
60
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);
68   }
69
70   virtual void TearDown() OVERRIDE {
71     // Kill the service before the profile.
72     if (service_)
73       service_->Shutdown();
74
75     service_.reset();
76     profile_.reset();
77
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();
83   }
84
85   // TODO(akalin): Refactor the StartSyncService*() functions below.
86
87   void StartSyncService() {
88     StartSyncServiceAndSetInitialSyncEnded(
89         true, true, false, true, syncer::STORAGE_IN_MEMORY);
90   }
91
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) {
98     if (service_)
99       return;
100
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(
109         factory,
110         profile_.get(),
111         signin,
112         oauth2_token_service,
113         ProfileSyncService::AUTO_START,
114         true));
115     if (!set_initial_sync_ended)
116       service_->dont_set_initial_sync_ended_on_init();
117
118     if (synchronous_sync_configuration)
119       service_->set_synchronous_sync_configuration();
120
121     service_->set_storage_option(storage_option);
122     if (!sync_setup_completed)
123       profile_->GetPrefs()->SetBoolean(prefs::kSyncHasSetupCompleted, false);
124
125     // Register the bookmark data type.
126     ON_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
127         WillByDefault(ReturnNewDataTypeManager());
128
129     if (issue_auth_token)
130       IssueTestTokens();
131
132     service_->Initialize();
133   }
134
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));
140       done.Wait();
141       base::RunLoop().RunUntilIdle();
142       if (service_->sync_initialized()) {
143         return;
144       }
145     }
146     LOG(ERROR) << "Backend not initialized.";
147   }
148
149   void IssueTestTokens() {
150     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())
151         ->UpdateCredentials("test", "oauth2_login_token");
152   }
153
154   scoped_ptr<TestProfileSyncService> service_;
155   scoped_ptr<TestingProfile> profile_;
156
157  private:
158   content::TestBrowserThreadBundle thread_bundle_;
159 };
160
161 class TestProfileSyncServiceObserver : public ProfileSyncServiceObserver {
162  public:
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();
167   }
168   bool first_setup_in_progress() const { return first_setup_in_progress_; }
169  private:
170   ProfileSyncService* service_;
171   bool first_setup_in_progress_;
172 };
173
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(),
181       profile_.get(),
182       signin,
183       oauth2_token_service,
184       ProfileSyncService::MANUAL_START,
185       true));
186   service_->Initialize();
187   EXPECT_TRUE(
188       service_->sync_service_url().spec() ==
189         ProfileSyncService::kSyncServerUrl ||
190       service_->sync_service_url().spec() ==
191         ProfileSyncService::kDevServerUrl);
192 }
193
194 // Tests that the sync service doesn't forget to notify observers about
195 // setup state.
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);
206 }
207
208 TEST_F(ProfileSyncServiceTest, DisabledByPolicy) {
209   profile_->GetTestingPrefService()->SetManagedPref(
210       prefs::kSyncManaged,
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(),
218       profile_.get(),
219       signin,
220       oauth2_token_service,
221       ProfileSyncService::MANUAL_START,
222       true));
223   service_->Initialize();
224   EXPECT_TRUE(service_->IsManaged());
225 }
226
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(
236       factory,
237       profile_.get(),
238       signin,
239       oauth2_token_service,
240       ProfileSyncService::AUTO_START,
241       true));
242   EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).Times(0);
243   EXPECT_CALL(*factory, CreateBookmarkSyncComponents(_, _)).
244       Times(0);
245   service_->RegisterDataTypeController(
246       new BookmarkDataTypeController(service_->factory(),
247                                      profile_.get(),
248                                      service_.get()));
249
250   service_->Initialize();
251   service_->Shutdown();
252   service_.reset();
253 }
254
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(
264       factory,
265       profile_.get(),
266       signin,
267       oauth2_token_service,
268       ProfileSyncService::AUTO_START,
269       true));
270   // Register the bookmark data type.
271   EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
272       WillRepeatedly(ReturnNewDataTypeManager());
273
274   IssueTestTokens();
275
276   service_->Initialize();
277   EXPECT_TRUE(service_->sync_initialized());
278   EXPECT_TRUE(service_->GetBackendForTest() != NULL);
279   EXPECT_FALSE(
280       profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
281
282   service_->StopAndSuppress();
283   EXPECT_FALSE(service_->sync_initialized());
284   EXPECT_TRUE(
285       profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
286
287   service_->UnsuppressAndStart();
288   EXPECT_TRUE(service_->sync_initialized());
289   EXPECT_FALSE(
290       profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
291 }
292
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)
296
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(
306       factory,
307       profile_.get(),
308       signin,
309       oauth2_token_service,
310       ProfileSyncService::AUTO_START,
311       true));
312   // Register the bookmark data type.
313   EXPECT_CALL(*factory, CreateDataTypeManager(_, _, _, _, _, _)).
314       WillRepeatedly(ReturnNewDataTypeManager());
315
316   IssueTestTokens();
317
318   service_->Initialize();
319   EXPECT_TRUE(service_->sync_initialized());
320   EXPECT_TRUE(service_->GetBackendForTest() != NULL);
321   EXPECT_FALSE(
322       profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart));
323
324   signin->SignOut();
325   EXPECT_FALSE(service_->sync_initialized());
326 }
327
328 #endif  // !defined(OS_CHROMEOS)
329
330 TEST_F(ProfileSyncServiceTest, JsControllerHandlersBasic) {
331   StartSyncService();
332   EXPECT_TRUE(service_->sync_initialized());
333   EXPECT_TRUE(service_->GetBackendForTest() != NULL);
334
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);
340 }
341
342 TEST_F(ProfileSyncServiceTest,
343        JsControllerHandlersDelayedBackendInitialization) {
344   StartSyncServiceAndSetInitialSyncEnded(true, false, false, true,
345                                                   syncer::STORAGE_IN_MEMORY);
346
347   StrictMock<syncer::MockJsEventHandler> event_handler;
348   EXPECT_CALL(event_handler, HandleJsEvent(_, _)).Times(AtLeast(1));
349
350   EXPECT_EQ(NULL, service_->GetBackendForTest());
351   EXPECT_FALSE(service_->sync_initialized());
352
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.
358   IssueTestTokens();
359   EXPECT_TRUE(service_->sync_initialized());
360   js_controller->RemoveJsEventHandler(&event_handler);
361 }
362
363 TEST_F(ProfileSyncServiceTest, JsControllerProcessJsMessageBasic) {
364   StartSyncService();
365   WaitForBackendInitDone();
366
367   StrictMock<syncer::MockJsReplyHandler> reply_handler;
368
369   ListValue arg_list1;
370   arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
371   syncer::JsArgList args1(&arg_list1);
372   EXPECT_CALL(reply_handler,
373               HandleJsReply("getNotificationState", HasArgs(args1)));
374
375   {
376     base::WeakPtr<syncer::JsController> js_controller =
377         service_->GetJsController();
378     js_controller->ProcessJsMessage("getNotificationState", args1,
379                                     reply_handler.AsWeakHandle());
380   }
381
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));
387   done.Wait();
388
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.
392   TearDown();
393 }
394
395 TEST_F(ProfileSyncServiceTest,
396        JsControllerProcessJsMessageBasicDelayedBackendInitialization) {
397   StartSyncServiceAndSetInitialSyncEnded(true, false, false, true,
398                                                   syncer::STORAGE_IN_MEMORY);
399
400   StrictMock<syncer::MockJsReplyHandler> reply_handler;
401
402   ListValue arg_list1;
403   arg_list1.Append(Value::CreateStringValue("INVALIDATIONS_ENABLED"));
404   syncer::JsArgList args1(&arg_list1);
405   EXPECT_CALL(reply_handler,
406               HandleJsReply("getNotificationState", HasArgs(args1)));
407
408   {
409     base::WeakPtr<syncer::JsController> js_controller =
410         service_->GetJsController();
411     js_controller->ProcessJsMessage("getNotificationState",
412                                     args1, reply_handler.AsWeakHandle());
413   }
414
415   IssueTestTokens();
416   WaitForBackendInitDone();
417
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));
423   done.Wait();
424 }
425
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));
439   ASSERT_NE(-1,
440             file_util::WriteFile(sync_file1, nonsense1, strlen(nonsense1)));
441   ASSERT_NE(-1,
442             file_util::WriteFile(sync_file2, nonsense2, strlen(nonsense2)));
443   ASSERT_NE(-1,
444             file_util::WriteFile(sync_file3, nonsense3, strlen(nonsense3)));
445
446   StartSyncServiceAndSetInitialSyncEnded(true, false, true, false,
447                                                   syncer::STORAGE_ON_DISK);
448   EXPECT_FALSE(service_->HasSyncSetupCompleted());
449   EXPECT_FALSE(service_->sync_initialized());
450
451   // Since we're doing synchronous initialization, backend should be
452   // initialized by this call.
453   IssueTestTokens();
454
455   // Stop the service so we can read the new Sync Data files that were
456   // created.
457   service_->Shutdown();
458   service_.reset();
459
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));
463
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);
469 }
470
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);
477
478   // The backend is not ready.  Ensure the PSS knows this.
479   EXPECT_FALSE(service_->sync_initialized());
480 }
481
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);
489
490   // The backend is not ready.  Ensure the PSS knows this.
491   EXPECT_FALSE(service_->sync_initialized());
492 }
493
494 }  // namespace
495 }  // namespace browser_sync