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 "chrome/browser/ui/webui/options/sync_setup_handler.h"
9 #include "base/command_line.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/signin/fake_signin_manager_builder.h"
16 #include "chrome/browser/signin/signin_error_controller_factory.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/sync/profile_sync_service_mock.h"
20 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
21 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/test/base/scoped_testing_local_state.h"
25 #include "chrome/test/base/testing_browser_process.h"
26 #include "chrome/test/base/testing_profile.h"
27 #include "components/signin/core/browser/fake_auth_status_provider.h"
28 #include "components/signin/core/browser/signin_manager.h"
29 #include "components/sync_driver/sync_prefs.h"
30 #include "content/public/browser/web_ui.h"
31 #include "content/public/test/test_browser_thread.h"
32 #include "content/public/test/test_browser_thread_bundle.h"
33 #include "content/public/test/test_web_ui.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "ui/base/layout.h"
38 using ::testing::Mock
;
39 using ::testing::Return
;
40 using ::testing::ReturnRef
;
41 using ::testing::Values
;
43 typedef GoogleServiceAuthError AuthError
;
47 MATCHER_P(ModelTypeSetMatches
, value
, "") { return arg
.Equals(value
); }
49 const char kTestUser
[] = "chrome.p13n.test@gmail.com";
51 // Returns a ModelTypeSet with all user selectable types set.
52 syncer::ModelTypeSet
GetAllTypes() {
53 return syncer::UserSelectableTypes();
56 enum SyncAllDataConfig
{
62 enum EncryptAllConfig
{
67 // Create a json-format string with the key/value pairs appropriate for a call
68 // to HandleConfigure(). If |extra_values| is non-null, then the values from
69 // the passed dictionary are added to the json.
70 std::string
GetConfiguration(const base::DictionaryValue
* extra_values
,
71 SyncAllDataConfig sync_all
,
72 syncer::ModelTypeSet types
,
73 const std::string
& passphrase
,
74 EncryptAllConfig encrypt_all
) {
75 base::DictionaryValue result
;
77 result
.MergeDictionary(extra_values
);
78 result
.SetBoolean("syncAllDataTypes", sync_all
== SYNC_ALL_DATA
);
79 result
.SetBoolean("syncNothing", sync_all
== SYNC_NOTHING
);
80 result
.SetBoolean("encryptAllData", encrypt_all
== ENCRYPT_ALL_DATA
);
81 result
.SetBoolean("usePassphrase", !passphrase
.empty());
82 if (!passphrase
.empty())
83 result
.SetString("passphrase", passphrase
);
84 // Add all of our data types.
85 result
.SetBoolean("appsSynced", types
.Has(syncer::APPS
));
86 result
.SetBoolean("autofillSynced", types
.Has(syncer::AUTOFILL
));
87 result
.SetBoolean("bookmarksSynced", types
.Has(syncer::BOOKMARKS
));
88 result
.SetBoolean("extensionsSynced", types
.Has(syncer::EXTENSIONS
));
89 result
.SetBoolean("passwordsSynced", types
.Has(syncer::PASSWORDS
));
90 result
.SetBoolean("preferencesSynced", types
.Has(syncer::PREFERENCES
));
91 result
.SetBoolean("tabsSynced", types
.Has(syncer::PROXY_TABS
));
92 result
.SetBoolean("themesSynced", types
.Has(syncer::THEMES
));
93 result
.SetBoolean("typedUrlsSynced", types
.Has(syncer::TYPED_URLS
));
94 result
.SetBoolean("wifiCredentialsSynced",
95 types
.Has(syncer::WIFI_CREDENTIALS
));
97 base::JSONWriter::Write(result
, &args
);
101 // Checks whether the passed |dictionary| contains a |key| with the given
102 // |expected_value|. If |omit_if_false| is true, then the value should only
103 // be present if |expected_value| is true.
104 void CheckBool(const base::DictionaryValue
* dictionary
,
105 const std::string
& key
,
107 bool omit_if_false
) {
108 if (omit_if_false
&& !expected_value
) {
109 EXPECT_FALSE(dictionary
->HasKey(key
)) <<
110 "Did not expect to find value for " << key
;
113 EXPECT_TRUE(dictionary
->GetBoolean(key
, &actual_value
)) <<
114 "No value found for " << key
;
115 EXPECT_EQ(expected_value
, actual_value
) <<
116 "Mismatch found for " << key
;
120 void CheckBool(const base::DictionaryValue
* dictionary
,
121 const std::string
& key
,
122 bool expected_value
) {
123 return CheckBool(dictionary
, key
, expected_value
, false);
126 // Checks to make sure that the values stored in |dictionary| match the values
127 // expected by the showSyncSetupPage() JS function for a given set of data
129 void CheckConfigDataTypeArguments(const base::DictionaryValue
* dictionary
,
130 SyncAllDataConfig config
,
131 syncer::ModelTypeSet types
) {
132 CheckBool(dictionary
, "syncAllDataTypes", config
== SYNC_ALL_DATA
);
133 CheckBool(dictionary
, "syncNothing", config
== SYNC_NOTHING
);
134 CheckBool(dictionary
, "appsSynced", types
.Has(syncer::APPS
));
135 CheckBool(dictionary
, "autofillSynced", types
.Has(syncer::AUTOFILL
));
136 CheckBool(dictionary
, "bookmarksSynced", types
.Has(syncer::BOOKMARKS
));
137 CheckBool(dictionary
, "extensionsSynced", types
.Has(syncer::EXTENSIONS
));
138 CheckBool(dictionary
, "passwordsSynced", types
.Has(syncer::PASSWORDS
));
139 CheckBool(dictionary
, "preferencesSynced", types
.Has(syncer::PREFERENCES
));
140 CheckBool(dictionary
, "tabsSynced", types
.Has(syncer::PROXY_TABS
));
141 CheckBool(dictionary
, "themesSynced", types
.Has(syncer::THEMES
));
142 CheckBool(dictionary
, "typedUrlsSynced", types
.Has(syncer::TYPED_URLS
));
143 CheckBool(dictionary
, "wifiCredentialsSynced",
144 types
.Has(syncer::WIFI_CREDENTIALS
));
150 class TestingSyncSetupHandler
: public SyncSetupHandler
{
152 TestingSyncSetupHandler(content::WebUI
* web_ui
, Profile
* profile
)
153 : profile_(profile
) {
156 ~TestingSyncSetupHandler() override
{ set_web_ui(NULL
); }
158 void FocusUI() override
{}
160 Profile
* GetProfile() const override
{ return profile_
; }
162 using SyncSetupHandler::is_configuring_sync
;
165 #if !defined(OS_CHROMEOS)
166 void DisplayGaiaLoginInNewTabOrWindow() override
{}
169 // Weak pointer to parent profile.
171 DISALLOW_COPY_AND_ASSIGN(TestingSyncSetupHandler
);
174 // The boolean parameter indicates whether the test is run with ClientOAuth
175 // or not. The test parameter is a bool: whether or not to test with/
176 // /ClientLogin enabled or not.
177 class SyncSetupHandlerTest
: public testing::Test
{
179 SyncSetupHandlerTest() : error_(GoogleServiceAuthError::NONE
) {}
180 void SetUp() override
{
181 error_
= GoogleServiceAuthError::AuthErrorNone();
183 TestingProfile::Builder builder
;
184 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
185 BuildFakeSigninManagerBase
);
186 profile_
= builder
.Build();
189 mock_signin_
= static_cast<SigninManagerBase
*>(
190 SigninManagerFactory::GetForProfile(profile_
.get()));
191 std::string username
= GetTestUser();
192 if (!username
.empty())
193 mock_signin_
->SetAuthenticatedAccountInfo(username
, username
);
195 mock_pss_
= static_cast<ProfileSyncServiceMock
*>(
196 ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
198 ProfileSyncServiceMock::BuildMockProfileSyncService
));
199 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
200 ON_CALL(*mock_pss_
, GetPassphraseType()).WillByDefault(
201 Return(syncer::IMPLICIT_PASSPHRASE
));
202 ON_CALL(*mock_pss_
, GetPassphraseTime()).WillByDefault(
203 Return(base::Time()));
204 ON_CALL(*mock_pss_
, GetExplicitPassphraseTime()).WillByDefault(
205 Return(base::Time()));
206 ON_CALL(*mock_pss_
, GetRegisteredDataTypes())
207 .WillByDefault(Return(syncer::ModelTypeSet()));
209 mock_pss_
->Initialize();
211 handler_
.reset(new TestingSyncSetupHandler(&web_ui_
, profile_
.get()));
214 // Setup the expectations for calls made when displaying the config page.
215 void SetDefaultExpectationsForConfigPage() {
216 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
217 EXPECT_CALL(*mock_pss_
, GetRegisteredDataTypes())
218 .WillRepeatedly(Return(GetAllTypes()));
219 EXPECT_CALL(*mock_pss_
, GetPreferredDataTypes())
220 .WillRepeatedly(Return(GetAllTypes()));
221 EXPECT_CALL(*mock_pss_
, GetActiveDataTypes())
222 .WillRepeatedly(Return(GetAllTypes()));
223 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingAllowed())
224 .WillRepeatedly(Return(true));
225 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingEnabled())
226 .WillRepeatedly(Return(false));
229 void SetupInitializedProfileSyncService() {
230 // An initialized ProfileSyncService will have already completed sync setup
231 // and will have an initialized sync backend.
232 ASSERT_TRUE(mock_signin_
->IsInitialized());
233 EXPECT_CALL(*mock_pss_
, IsBackendInitialized())
234 .WillRepeatedly(Return(true));
237 void ExpectConfig() {
238 ASSERT_EQ(1U, web_ui_
.call_data().size());
239 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
240 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
242 ASSERT_TRUE(data
.arg1()->GetAsString(&page
));
243 EXPECT_EQ(page
, "configure");
247 ASSERT_EQ(1U, web_ui_
.call_data().size());
248 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
249 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
251 ASSERT_TRUE(data
.arg1()->GetAsString(&page
));
252 EXPECT_EQ(page
, "done");
255 void ExpectSpinnerAndClose() {
256 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
257 EXPECT_EQ(1U, web_ui_
.call_data().size());
258 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
259 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
262 ASSERT_TRUE(data
.arg1()->GetAsString(&page
));
263 EXPECT_EQ(page
, "spinner");
264 // Cancelling the spinner dialog will cause CloseSyncSetup().
265 handler_
->CloseSyncSetup();
267 LoginUIServiceFactory::GetForProfile(
268 profile_
.get())->current_login_ui());
271 // It's difficult to notify sync listeners when using a ProfileSyncServiceMock
272 // so this helper routine dispatches an OnStateChanged() notification to the
273 // SyncStartupTracker.
274 void NotifySyncListeners() {
275 if (handler_
->sync_startup_tracker_
)
276 handler_
->sync_startup_tracker_
->OnStateChanged();
279 virtual std::string
GetTestUser() {
280 return std::string(kTestUser
);
283 content::TestBrowserThreadBundle thread_bundle_
;
284 scoped_ptr
<Profile
> profile_
;
285 ProfileSyncServiceMock
* mock_pss_
;
286 GoogleServiceAuthError error_
;
287 SigninManagerBase
* mock_signin_
;
288 content::TestWebUI web_ui_
;
289 scoped_ptr
<TestingSyncSetupHandler
> handler_
;
292 class SyncSetupHandlerFirstSigninTest
: public SyncSetupHandlerTest
{
293 std::string
GetTestUser() override
{ return std::string(); }
296 TEST_F(SyncSetupHandlerTest
, Basic
) {
299 #if !defined(OS_CHROMEOS)
300 TEST_F(SyncSetupHandlerFirstSigninTest
, DisplayBasicLogin
) {
301 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(false));
302 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
303 .WillRepeatedly(Return(false));
304 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
305 .WillRepeatedly(Return(false));
306 // Ensure that the user is not signed in before calling |HandleStartSignin()|.
307 SigninManager
* manager
= static_cast<SigninManager
*>(mock_signin_
);
308 manager
->SignOut(signin_metrics::SIGNOUT_TEST
);
309 handler_
->HandleStartSignin(NULL
);
311 // Sync setup hands off control to the gaia login tab.
313 LoginUIServiceFactory::GetForProfile(
314 profile_
.get())->current_login_ui());
316 ASSERT_FALSE(handler_
->is_configuring_sync());
318 handler_
->CloseSyncSetup();
320 LoginUIServiceFactory::GetForProfile(
321 profile_
.get())->current_login_ui());
324 TEST_F(SyncSetupHandlerTest
, ShowSyncSetupWhenNotSignedIn
) {
325 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(false));
326 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
327 .WillRepeatedly(Return(false));
328 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
329 .WillRepeatedly(Return(false));
330 handler_
->HandleShowSetupUI(NULL
);
332 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
333 ASSERT_EQ(1U, web_ui_
.call_data().size());
334 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
335 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
337 ASSERT_FALSE(handler_
->is_configuring_sync());
339 LoginUIServiceFactory::GetForProfile(
340 profile_
.get())->current_login_ui());
342 #endif // !defined(OS_CHROMEOS)
344 // Verifies that the sync setup is terminated correctly when the
346 TEST_F(SyncSetupHandlerTest
, HandleSetupUIWhenSyncDisabled
) {
347 EXPECT_CALL(*mock_pss_
, IsManaged()).WillRepeatedly(Return(true));
348 handler_
->HandleShowSetupUI(NULL
);
350 // Sync setup is closed when sync is disabled.
352 LoginUIServiceFactory::GetForProfile(
353 profile_
.get())->current_login_ui());
354 ASSERT_FALSE(handler_
->is_configuring_sync());
357 // Verifies that the handler correctly handles a cancellation when
358 // it is displaying the spinner to the user.
359 TEST_F(SyncSetupHandlerTest
, DisplayConfigureWithBackendDisabledAndCancel
) {
360 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
361 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
362 .WillRepeatedly(Return(true));
363 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
364 .WillRepeatedly(Return(false));
365 error_
= GoogleServiceAuthError::AuthErrorNone();
366 EXPECT_CALL(*mock_pss_
, IsBackendInitialized()).WillRepeatedly(Return(false));
368 // We're simulating a user setting up sync, which would cause the backend to
369 // kick off initialization, but not download user data types. The sync
370 // backend will try to download control data types (e.g encryption info), but
371 // that won't finish for this test as we're simulating cancelling while the
372 // spinner is showing.
373 handler_
->HandleShowSetupUI(NULL
);
375 EXPECT_EQ(handler_
.get(),
376 LoginUIServiceFactory::GetForProfile(
377 profile_
.get())->current_login_ui());
379 ExpectSpinnerAndClose();
382 // Verifies that the handler correctly transitions from showing the spinner
383 // to showing a configuration page when sync setup completes successfully.
384 TEST_F(SyncSetupHandlerTest
,
385 DisplayConfigureWithBackendDisabledAndSyncStartupCompleted
) {
386 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
387 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
388 .WillRepeatedly(Return(true));
389 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
390 .WillRepeatedly(Return(false));
391 error_
= GoogleServiceAuthError::AuthErrorNone();
392 // Sync backend is stopped initially, and will start up.
393 EXPECT_CALL(*mock_pss_
, IsBackendInitialized()).WillRepeatedly(Return(false));
394 SetDefaultExpectationsForConfigPage();
396 handler_
->OpenSyncSetup();
398 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
399 EXPECT_EQ(1U, web_ui_
.call_data().size());
401 const content::TestWebUI::CallData
& data0
= *web_ui_
.call_data()[0];
402 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data0
.function_name());
404 ASSERT_TRUE(data0
.arg1()->GetAsString(&page
));
405 EXPECT_EQ(page
, "spinner");
407 Mock::VerifyAndClearExpectations(mock_pss_
);
408 // Now, act as if the ProfileSyncService has started up.
409 SetDefaultExpectationsForConfigPage();
410 EXPECT_CALL(*mock_pss_
, IsBackendInitialized()).WillRepeatedly(Return(true));
411 error_
= GoogleServiceAuthError::AuthErrorNone();
412 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
413 NotifySyncListeners();
415 // We expect a second call to SyncSetupOverlay.showSyncSetupPage.
416 EXPECT_EQ(2U, web_ui_
.call_data().size());
417 const content::TestWebUI::CallData
& data1
= *web_ui_
.call_data().back();
418 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data1
.function_name());
419 ASSERT_TRUE(data1
.arg1()->GetAsString(&page
));
420 EXPECT_EQ(page
, "configure");
421 const base::DictionaryValue
* dictionary
= nullptr;
422 ASSERT_TRUE(data1
.arg2()->GetAsDictionary(&dictionary
));
423 CheckBool(dictionary
, "passphraseFailed", false);
424 CheckBool(dictionary
, "syncAllDataTypes", true);
425 CheckBool(dictionary
, "encryptAllDataAllowed", true);
426 CheckBool(dictionary
, "encryptAllData", false);
427 CheckBool(dictionary
, "usePassphrase", false);
430 // Verifies the case where the user cancels after the sync backend has
431 // initialized (meaning it already transitioned from the spinner to a proper
432 // configuration page, tested by
433 // DisplayConfigureWithBackendDisabledAndSigninSuccess), but before the user
434 // before the user has continued on.
435 TEST_F(SyncSetupHandlerTest
,
436 DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess
) {
437 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
438 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
439 .WillRepeatedly(Return(true));
440 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
441 .WillRepeatedly(Return(false));
442 error_
= GoogleServiceAuthError::AuthErrorNone();
443 EXPECT_CALL(*mock_pss_
, IsBackendInitialized())
444 .WillOnce(Return(false))
445 .WillRepeatedly(Return(true));
446 SetDefaultExpectationsForConfigPage();
447 handler_
->OpenSyncSetup();
449 // It's important to tell sync the user cancelled the setup flow before we
450 // tell it we're through with the setup progress.
451 testing::InSequence seq
;
452 EXPECT_CALL(*mock_pss_
, RequestStop(ProfileSyncService::CLEAR_DATA
));
453 EXPECT_CALL(*mock_pss_
, SetSetupInProgress(false));
455 handler_
->CloseSyncSetup();
457 LoginUIServiceFactory::GetForProfile(
458 profile_
.get())->current_login_ui());
461 TEST_F(SyncSetupHandlerTest
,
462 DisplayConfigureWithBackendDisabledAndSigninFailed
) {
463 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
464 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
465 .WillRepeatedly(Return(true));
466 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
467 .WillRepeatedly(Return(false));
468 error_
= GoogleServiceAuthError::AuthErrorNone();
469 EXPECT_CALL(*mock_pss_
, IsBackendInitialized()).WillRepeatedly(Return(false));
471 handler_
->OpenSyncSetup();
472 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
473 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
475 ASSERT_TRUE(data
.arg1()->GetAsString(&page
));
476 EXPECT_EQ(page
, "spinner");
477 Mock::VerifyAndClearExpectations(mock_pss_
);
478 error_
= GoogleServiceAuthError(
479 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
480 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
481 NotifySyncListeners();
483 // On failure, the dialog will be closed.
485 LoginUIServiceFactory::GetForProfile(
486 profile_
.get())->current_login_ui());
489 #if !defined(OS_CHROMEOS)
491 class SyncSetupHandlerNonCrosTest
: public SyncSetupHandlerTest
{
493 SyncSetupHandlerNonCrosTest() {}
496 TEST_F(SyncSetupHandlerNonCrosTest
, HandleGaiaAuthFailure
) {
497 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(false));
498 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
499 .WillRepeatedly(Return(false));
500 EXPECT_CALL(*mock_pss_
, HasUnrecoverableError())
501 .WillRepeatedly(Return(false));
502 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
503 .WillRepeatedly(Return(false));
505 handler_
->OpenSyncSetup();
507 ASSERT_FALSE(handler_
->is_configuring_sync());
510 // TODO(kochi): We need equivalent tests for ChromeOS.
511 TEST_F(SyncSetupHandlerNonCrosTest
, UnrecoverableErrorInitializingSync
) {
512 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(false));
513 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
514 .WillRepeatedly(Return(false));
515 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
516 .WillRepeatedly(Return(false));
518 handler_
->OpenSyncSetup();
520 ASSERT_FALSE(handler_
->is_configuring_sync());
523 TEST_F(SyncSetupHandlerNonCrosTest
, GaiaErrorInitializingSync
) {
524 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(false));
525 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
526 .WillRepeatedly(Return(false));
527 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
528 .WillRepeatedly(Return(false));
530 handler_
->OpenSyncSetup();
532 ASSERT_FALSE(handler_
->is_configuring_sync());
535 #endif // #if !defined(OS_CHROMEOS)
537 TEST_F(SyncSetupHandlerTest
, TestSyncEverything
) {
538 std::string args
= GetConfiguration(
539 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
540 base::ListValue list_args
;
541 list_args
.Append(new base::StringValue(args
));
542 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
543 .WillRepeatedly(Return(false));
544 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
545 .WillRepeatedly(Return(false));
546 SetupInitializedProfileSyncService();
547 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(true, _
));
548 handler_
->HandleConfigure(&list_args
);
550 // Ensure that we navigated to the "done" state since we don't need a
555 TEST_F(SyncSetupHandlerTest
, TestSyncNothing
) {
556 std::string args
= GetConfiguration(
557 NULL
, SYNC_NOTHING
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
558 base::ListValue list_args
;
559 list_args
.Append(new base::StringValue(args
));
560 EXPECT_CALL(*mock_pss_
, RequestStop(ProfileSyncService::CLEAR_DATA
));
561 SetupInitializedProfileSyncService();
562 handler_
->HandleConfigure(&list_args
);
564 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
565 ASSERT_EQ(1U, web_ui_
.call_data().size());
566 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
567 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name());
570 TEST_F(SyncSetupHandlerTest
, TurnOnEncryptAll
) {
571 std::string args
= GetConfiguration(
572 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA
);
573 base::ListValue list_args
;
574 list_args
.Append(new base::StringValue(args
));
575 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
576 .WillRepeatedly(Return(false));
577 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
578 .WillRepeatedly(Return(false));
579 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingAllowed())
580 .WillRepeatedly(Return(true));
581 SetupInitializedProfileSyncService();
582 EXPECT_CALL(*mock_pss_
, EnableEncryptEverything());
583 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(true, _
));
584 handler_
->HandleConfigure(&list_args
);
586 // Ensure that we navigated to the "done" state since we don't need a
591 TEST_F(SyncSetupHandlerTest
, TestPassphraseStillRequired
) {
592 std::string args
= GetConfiguration(
593 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
594 base::ListValue list_args
;
595 list_args
.Append(new base::StringValue(args
));
596 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
597 .WillRepeatedly(Return(true));
598 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
599 .WillRepeatedly(Return(true));
600 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
601 .WillRepeatedly(Return(false));
602 SetupInitializedProfileSyncService();
603 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
604 SetDefaultExpectationsForConfigPage();
606 // We should navigate back to the configure page since we need a passphrase.
607 handler_
->HandleConfigure(&list_args
);
612 TEST_F(SyncSetupHandlerTest
, SuccessfullySetPassphrase
) {
613 base::DictionaryValue dict
;
614 dict
.SetBoolean("isGooglePassphrase", true);
615 std::string args
= GetConfiguration(&dict
,
620 base::ListValue list_args
;
621 list_args
.Append(new base::StringValue(args
));
622 // Act as if an encryption passphrase is required the first time, then never
624 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired()).WillOnce(Return(true));
625 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
626 .WillRepeatedly(Return(false));
627 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
628 .WillRepeatedly(Return(false));
629 SetupInitializedProfileSyncService();
630 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
631 EXPECT_CALL(*mock_pss_
, SetDecryptionPassphrase("gaiaPassphrase")).
632 WillOnce(Return(true));
634 handler_
->HandleConfigure(&list_args
);
635 // We should navigate to "done" page since we finished configuring.
639 TEST_F(SyncSetupHandlerTest
, SelectCustomEncryption
) {
640 base::DictionaryValue dict
;
641 dict
.SetBoolean("isGooglePassphrase", false);
642 std::string args
= GetConfiguration(&dict
,
647 base::ListValue list_args
;
648 list_args
.Append(new base::StringValue(args
));
649 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
650 .WillRepeatedly(Return(false));
651 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
652 .WillRepeatedly(Return(false));
653 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
654 .WillRepeatedly(Return(false));
655 SetupInitializedProfileSyncService();
656 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
657 EXPECT_CALL(*mock_pss_
,
658 SetEncryptionPassphrase("custom_passphrase",
659 ProfileSyncService::EXPLICIT
));
661 handler_
->HandleConfigure(&list_args
);
662 // We should navigate to "done" page since we finished configuring.
666 TEST_F(SyncSetupHandlerTest
, UnsuccessfullySetPassphrase
) {
667 base::DictionaryValue dict
;
668 dict
.SetBoolean("isGooglePassphrase", true);
669 std::string args
= GetConfiguration(&dict
,
672 "invalid_passphrase",
674 base::ListValue list_args
;
675 list_args
.Append(new base::StringValue(args
));
676 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
677 .WillRepeatedly(Return(true));
678 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
679 .WillRepeatedly(Return(true));
680 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
681 .WillRepeatedly(Return(false));
682 SetupInitializedProfileSyncService();
683 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
684 EXPECT_CALL(*mock_pss_
, SetDecryptionPassphrase("invalid_passphrase")).
685 WillOnce(Return(false));
687 SetDefaultExpectationsForConfigPage();
688 // We should navigate back to the configure page since we need a passphrase.
689 handler_
->HandleConfigure(&list_args
);
693 // Make sure we display an error message to the user due to the failed
695 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
696 const base::DictionaryValue
* dictionary
= nullptr;
697 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
698 CheckBool(dictionary
, "passphraseFailed", true);
701 // Walks through each user selectable type, and tries to sync just that single
703 TEST_F(SyncSetupHandlerTest
, TestSyncIndividualTypes
) {
704 syncer::ModelTypeSet user_selectable_types
= GetAllTypes();
705 syncer::ModelTypeSet::Iterator it
;
706 for (it
= user_selectable_types
.First(); it
.Good(); it
.Inc()) {
707 syncer::ModelTypeSet type_to_set
;
708 type_to_set
.Put(it
.Get());
709 std::string args
= GetConfiguration(NULL
,
714 base::ListValue list_args
;
715 list_args
.Append(new base::StringValue(args
));
716 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
717 .WillRepeatedly(Return(false));
718 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
719 .WillRepeatedly(Return(false));
720 SetupInitializedProfileSyncService();
721 EXPECT_CALL(*mock_pss_
,
722 OnUserChoseDatatypes(false, ModelTypeSetMatches(type_to_set
)));
723 handler_
->HandleConfigure(&list_args
);
726 Mock::VerifyAndClearExpectations(mock_pss_
);
727 web_ui_
.ClearTrackedCalls();
731 TEST_F(SyncSetupHandlerTest
, TestSyncAllManually
) {
732 std::string args
= GetConfiguration(NULL
,
737 base::ListValue list_args
;
738 list_args
.Append(new base::StringValue(args
));
739 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
740 .WillRepeatedly(Return(false));
741 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
742 .WillRepeatedly(Return(false));
743 SetupInitializedProfileSyncService();
744 EXPECT_CALL(*mock_pss_
,
745 OnUserChoseDatatypes(false, ModelTypeSetMatches(GetAllTypes())));
746 handler_
->HandleConfigure(&list_args
);
751 TEST_F(SyncSetupHandlerTest
, ShowSyncSetup
) {
752 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
753 .WillRepeatedly(Return(false));
754 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
755 .WillRepeatedly(Return(false));
756 SetupInitializedProfileSyncService();
757 // This should display the sync setup dialog (not login).
758 SetDefaultExpectationsForConfigPage();
759 handler_
->OpenSyncSetup();
764 // We do not display signin on chromeos in the case of auth error.
765 TEST_F(SyncSetupHandlerTest
, ShowSigninOnAuthError
) {
766 // Initialize the system to a signed in state, but with an auth error.
767 error_
= GoogleServiceAuthError(
768 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
770 SetupInitializedProfileSyncService();
771 mock_signin_
->SetAuthenticatedAccountInfo(kTestUser
, kTestUser
);
772 FakeAuthStatusProvider
provider(
773 SigninErrorControllerFactory::GetForProfile(profile_
.get()));
774 provider
.SetAuthError(kTestUser
, error_
);
775 EXPECT_CALL(*mock_pss_
, CanSyncStart()).WillRepeatedly(Return(true));
776 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
777 .WillRepeatedly(Return(true));
778 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
779 .WillRepeatedly(Return(false));
780 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
781 .WillRepeatedly(Return(false));
782 EXPECT_CALL(*mock_pss_
, IsBackendInitialized()).WillRepeatedly(Return(false));
784 #if defined(OS_CHROMEOS)
785 // On ChromeOS, auth errors are ignored - instead we just try to start the
786 // sync backend (which will fail due to the auth error). This should only
787 // happen if the user manually navigates to chrome://settings/syncSetup -
788 // clicking on the button in the UI will sign the user out rather than
789 // displaying a spinner. Should be no visible UI on ChromeOS in this case.
790 EXPECT_EQ(NULL
, LoginUIServiceFactory::GetForProfile(
791 profile_
.get())->current_login_ui());
794 // On ChromeOS, this should display the spinner while we try to startup the
795 // sync backend, and on desktop this displays the login dialog.
796 handler_
->OpenSyncSetup();
798 // Sync setup is closed when re-auth is in progress.
800 LoginUIServiceFactory::GetForProfile(
801 profile_
.get())->current_login_ui());
803 ASSERT_FALSE(handler_
->is_configuring_sync());
807 TEST_F(SyncSetupHandlerTest
, ShowSetupSyncEverything
) {
808 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
809 .WillRepeatedly(Return(false));
810 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
811 .WillRepeatedly(Return(false));
812 SetupInitializedProfileSyncService();
813 SetDefaultExpectationsForConfigPage();
814 // This should display the sync setup dialog (not login).
815 handler_
->OpenSyncSetup();
818 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
819 const base::DictionaryValue
* dictionary
= nullptr;
820 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
821 CheckBool(dictionary
, "syncAllDataTypes", true);
822 CheckBool(dictionary
, "appsRegistered", true);
823 CheckBool(dictionary
, "autofillRegistered", true);
824 CheckBool(dictionary
, "bookmarksRegistered", true);
825 CheckBool(dictionary
, "extensionsRegistered", true);
826 CheckBool(dictionary
, "passwordsRegistered", true);
827 CheckBool(dictionary
, "preferencesRegistered", true);
828 CheckBool(dictionary
, "wifiCredentialsRegistered", true);
829 CheckBool(dictionary
, "tabsRegistered", true);
830 CheckBool(dictionary
, "themesRegistered", true);
831 CheckBool(dictionary
, "typedUrlsRegistered", true);
832 CheckBool(dictionary
, "showPassphrase", false);
833 CheckBool(dictionary
, "usePassphrase", false);
834 CheckBool(dictionary
, "passphraseFailed", false);
835 CheckBool(dictionary
, "encryptAllData", false);
836 CheckConfigDataTypeArguments(dictionary
, SYNC_ALL_DATA
, GetAllTypes());
839 TEST_F(SyncSetupHandlerTest
, ShowSetupManuallySyncAll
) {
840 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
841 .WillRepeatedly(Return(false));
842 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
843 .WillRepeatedly(Return(false));
844 SetupInitializedProfileSyncService();
845 sync_driver::SyncPrefs
sync_prefs(profile_
->GetPrefs());
846 sync_prefs
.SetKeepEverythingSynced(false);
847 SetDefaultExpectationsForConfigPage();
848 // This should display the sync setup dialog (not login).
849 handler_
->OpenSyncSetup();
852 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
853 const base::DictionaryValue
* dictionary
= nullptr;
854 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
855 CheckConfigDataTypeArguments(dictionary
, CHOOSE_WHAT_TO_SYNC
, GetAllTypes());
858 TEST_F(SyncSetupHandlerTest
, ShowSetupSyncForAllTypesIndividually
) {
859 syncer::ModelTypeSet user_selectable_types
= GetAllTypes();
860 syncer::ModelTypeSet::Iterator it
;
861 for (it
= user_selectable_types
.First(); it
.Good(); it
.Inc()) {
862 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
863 .WillRepeatedly(Return(false));
864 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
865 .WillRepeatedly(Return(false));
866 SetupInitializedProfileSyncService();
867 sync_driver::SyncPrefs
sync_prefs(profile_
->GetPrefs());
868 sync_prefs
.SetKeepEverythingSynced(false);
869 SetDefaultExpectationsForConfigPage();
870 syncer::ModelTypeSet types
;
872 EXPECT_CALL(*mock_pss_
, GetPreferredDataTypes()).
873 WillRepeatedly(Return(types
));
875 // This should display the sync setup dialog (not login).
876 handler_
->OpenSyncSetup();
879 // Close the config overlay.
880 LoginUIServiceFactory::GetForProfile(profile_
.get())->LoginUIClosed(
882 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
883 const base::DictionaryValue
* dictionary
= nullptr;
884 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
885 CheckConfigDataTypeArguments(dictionary
, CHOOSE_WHAT_TO_SYNC
, types
);
886 Mock::VerifyAndClearExpectations(mock_pss_
);
887 // Clean up so we can loop back to display the dialog again.
888 web_ui_
.ClearTrackedCalls();
892 TEST_F(SyncSetupHandlerTest
, ShowSetupGaiaPassphraseRequired
) {
893 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
894 .WillRepeatedly(Return(true));
895 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
896 .WillRepeatedly(Return(false));
897 SetupInitializedProfileSyncService();
898 SetDefaultExpectationsForConfigPage();
900 // This should display the sync setup dialog (not login).
901 handler_
->OpenSyncSetup();
904 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
905 const base::DictionaryValue
* dictionary
= nullptr;
906 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
907 CheckBool(dictionary
, "showPassphrase", true);
908 CheckBool(dictionary
, "usePassphrase", false);
909 CheckBool(dictionary
, "passphraseFailed", false);
912 TEST_F(SyncSetupHandlerTest
, ShowSetupCustomPassphraseRequired
) {
913 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
914 .WillRepeatedly(Return(true));
915 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
916 .WillRepeatedly(Return(true));
917 EXPECT_CALL(*mock_pss_
, GetPassphraseType())
918 .WillRepeatedly(Return(syncer::CUSTOM_PASSPHRASE
));
919 SetupInitializedProfileSyncService();
920 SetDefaultExpectationsForConfigPage();
922 // This should display the sync setup dialog (not login).
923 handler_
->OpenSyncSetup();
926 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
927 const base::DictionaryValue
* dictionary
= nullptr;
928 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
929 CheckBool(dictionary
, "showPassphrase", true);
930 CheckBool(dictionary
, "usePassphrase", true);
931 CheckBool(dictionary
, "passphraseFailed", false);
934 TEST_F(SyncSetupHandlerTest
, ShowSetupEncryptAll
) {
935 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
936 .WillRepeatedly(Return(false));
937 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
938 .WillRepeatedly(Return(false));
939 SetupInitializedProfileSyncService();
940 SetDefaultExpectationsForConfigPage();
941 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingEnabled())
942 .WillRepeatedly(Return(true));
944 // This should display the sync setup dialog (not login).
945 handler_
->OpenSyncSetup();
948 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
949 const base::DictionaryValue
* dictionary
= nullptr;
950 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
951 CheckBool(dictionary
, "encryptAllData", true);
954 TEST_F(SyncSetupHandlerTest
, ShowSetupEncryptAllDisallowed
) {
955 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
956 .WillRepeatedly(Return(false));
957 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
958 .WillRepeatedly(Return(false));
959 SetupInitializedProfileSyncService();
960 SetDefaultExpectationsForConfigPage();
961 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingAllowed())
962 .WillRepeatedly(Return(false));
964 // This should display the sync setup dialog (not login).
965 handler_
->OpenSyncSetup();
968 const content::TestWebUI::CallData
& data
= *web_ui_
.call_data()[0];
969 const base::DictionaryValue
* dictionary
= nullptr;
970 ASSERT_TRUE(data
.arg2()->GetAsDictionary(&dictionary
));
971 CheckBool(dictionary
, "encryptAllData", false);
972 CheckBool(dictionary
, "encryptAllDataAllowed", false);
975 TEST_F(SyncSetupHandlerTest
, TurnOnEncryptAllDisallowed
) {
976 std::string args
= GetConfiguration(
977 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA
);
978 base::ListValue list_args
;
979 list_args
.Append(new base::StringValue(args
));
980 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
981 .WillRepeatedly(Return(false));
982 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
983 .WillRepeatedly(Return(false));
984 SetupInitializedProfileSyncService();
985 EXPECT_CALL(*mock_pss_
, IsEncryptEverythingAllowed())
986 .WillRepeatedly(Return(false));
987 EXPECT_CALL(*mock_pss_
, EnableEncryptEverything()).Times(0);
988 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(true, _
));
989 handler_
->HandleConfigure(&list_args
);
991 // Ensure that we navigated to the "done" state since we don't need a