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/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_auth_status_provider.h"
16 #include "chrome/browser/signin/fake_signin_manager.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_manager.h"
20 #include "chrome/browser/signin/signin_manager_factory.h"
21 #include "chrome/browser/sync/profile_sync_service_factory.h"
22 #include "chrome/browser/sync/profile_sync_service_mock.h"
23 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
24 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_browser_process.h"
29 #include "chrome/test/base/scoped_testing_local_state.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 "grit/generated_resources.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/layout.h"
39 using ::testing::Mock
;
40 using ::testing::Return
;
41 using ::testing::ReturnRef
;
42 using ::testing::Values
;
44 typedef GoogleServiceAuthError AuthError
;
48 MATCHER_P(ModelTypeSetMatches
, value
, "") { return arg
.Equals(value
); }
50 const char kTestUser
[] = "chrome.p13n.test@gmail.com";
52 // Returns a ModelTypeSet with all user selectable types set.
53 syncer::ModelTypeSet
GetAllTypes() {
54 return syncer::UserSelectableTypes();
57 enum SyncAllDataConfig
{
63 enum EncryptAllConfig
{
68 // Create a json-format string with the key/value pairs appropriate for a call
69 // to HandleConfigure(). If |extra_values| is non-null, then the values from
70 // the passed dictionary are added to the json.
71 std::string
GetConfiguration(const base::DictionaryValue
* extra_values
,
72 SyncAllDataConfig sync_all
,
73 syncer::ModelTypeSet types
,
74 const std::string
& passphrase
,
75 EncryptAllConfig encrypt_all
) {
76 base::DictionaryValue result
;
78 result
.MergeDictionary(extra_values
);
79 result
.SetBoolean("syncAllDataTypes", sync_all
== SYNC_ALL_DATA
);
80 result
.SetBoolean("syncNothing", sync_all
== SYNC_NOTHING
);
81 result
.SetBoolean("encryptAllData", encrypt_all
== ENCRYPT_ALL_DATA
);
82 result
.SetBoolean("usePassphrase", !passphrase
.empty());
83 if (!passphrase
.empty())
84 result
.SetString("passphrase", passphrase
);
85 // Add all of our data types.
86 result
.SetBoolean("appsSynced", types
.Has(syncer::APPS
));
87 result
.SetBoolean("autofillSynced", types
.Has(syncer::AUTOFILL
));
88 result
.SetBoolean("bookmarksSynced", types
.Has(syncer::BOOKMARKS
));
89 result
.SetBoolean("extensionsSynced", types
.Has(syncer::EXTENSIONS
));
90 result
.SetBoolean("passwordsSynced", types
.Has(syncer::PASSWORDS
));
91 result
.SetBoolean("preferencesSynced", types
.Has(syncer::PREFERENCES
));
92 result
.SetBoolean("tabsSynced", types
.Has(syncer::PROXY_TABS
));
93 result
.SetBoolean("themesSynced", types
.Has(syncer::THEMES
));
94 result
.SetBoolean("typedUrlsSynced", types
.Has(syncer::TYPED_URLS
));
96 base::JSONWriter::Write(&result
, &args
);
100 // Checks whether the passed |dictionary| contains a |key| with the given
101 // |expected_value|. If |omit_if_false| is true, then the value should only
102 // be present if |expected_value| is true.
103 void CheckBool(const base::DictionaryValue
* dictionary
,
104 const std::string
& key
,
106 bool omit_if_false
) {
107 if (omit_if_false
&& !expected_value
) {
108 EXPECT_FALSE(dictionary
->HasKey(key
)) <<
109 "Did not expect to find value for " << key
;
112 EXPECT_TRUE(dictionary
->GetBoolean(key
, &actual_value
)) <<
113 "No value found for " << key
;
114 EXPECT_EQ(actual_value
, expected_value
) <<
115 "Mismatch found for " << key
;
119 void CheckBool(const base::DictionaryValue
* dictionary
,
120 const std::string
& key
,
121 bool expected_value
) {
122 return CheckBool(dictionary
, key
, expected_value
, false);
125 // Checks to make sure that the values stored in |dictionary| match the values
126 // expected by the showSyncSetupPage() JS function for a given set of data
128 void CheckConfigDataTypeArguments(base::DictionaryValue
* dictionary
,
129 SyncAllDataConfig config
,
130 syncer::ModelTypeSet types
) {
131 CheckBool(dictionary
, "syncAllDataTypes", config
== SYNC_ALL_DATA
);
132 CheckBool(dictionary
, "syncNothing", config
== SYNC_NOTHING
);
133 CheckBool(dictionary
, "appsSynced", types
.Has(syncer::APPS
));
134 CheckBool(dictionary
, "autofillSynced", types
.Has(syncer::AUTOFILL
));
135 CheckBool(dictionary
, "bookmarksSynced", types
.Has(syncer::BOOKMARKS
));
136 CheckBool(dictionary
, "extensionsSynced", types
.Has(syncer::EXTENSIONS
));
137 CheckBool(dictionary
, "passwordsSynced", types
.Has(syncer::PASSWORDS
));
138 CheckBool(dictionary
, "preferencesSynced", types
.Has(syncer::PREFERENCES
));
139 CheckBool(dictionary
, "tabsSynced", types
.Has(syncer::PROXY_TABS
));
140 CheckBool(dictionary
, "themesSynced", types
.Has(syncer::THEMES
));
141 CheckBool(dictionary
, "typedUrlsSynced", types
.Has(syncer::TYPED_URLS
));
147 // Test instance of WebUI that tracks the data passed to
148 // CallJavascriptFunction().
149 class TestWebUI
: public content::WebUI
{
151 virtual ~TestWebUI() {
155 void ClearTrackedCalls() {
156 // Manually free the arguments stored in CallData, since there's no good
157 // way to use a self-freeing reference like scoped_ptr in a std::vector.
158 for (std::vector
<CallData
>::iterator i
= call_data_
.begin();
159 i
!= call_data_
.end();
167 virtual void CallJavascriptFunction(const std::string
& function_name
)
169 call_data_
.push_back(CallData());
170 call_data_
.back().function_name
= function_name
;
173 virtual void CallJavascriptFunction(const std::string
& function_name
,
174 const base::Value
& arg1
) OVERRIDE
{
175 call_data_
.push_back(CallData());
176 call_data_
.back().function_name
= function_name
;
177 call_data_
.back().arg1
= arg1
.DeepCopy();
180 virtual void CallJavascriptFunction(const std::string
& function_name
,
181 const base::Value
& arg1
,
182 const base::Value
& arg2
) OVERRIDE
{
183 call_data_
.push_back(CallData());
184 call_data_
.back().function_name
= function_name
;
185 call_data_
.back().arg1
= arg1
.DeepCopy();
186 call_data_
.back().arg2
= arg2
.DeepCopy();
189 virtual content::WebContents
* GetWebContents() const OVERRIDE
{
192 virtual content::WebUIController
* GetController() const OVERRIDE
{
195 virtual void SetController(content::WebUIController
* controller
) OVERRIDE
{}
196 virtual ui::ScaleFactor
GetDeviceScaleFactor() const OVERRIDE
{
197 return ui::SCALE_FACTOR_100P
;
199 virtual const base::string16
& GetOverriddenTitle() const OVERRIDE
{
202 virtual void OverrideTitle(const base::string16
& title
) OVERRIDE
{}
203 virtual content::PageTransition
GetLinkTransitionType() const OVERRIDE
{
204 return content::PAGE_TRANSITION_LINK
;
206 virtual void SetLinkTransitionType(content::PageTransition type
) OVERRIDE
{}
207 virtual int GetBindings() const OVERRIDE
{
210 virtual void SetBindings(int bindings
) OVERRIDE
{}
211 virtual void SetFrameXPath(const std::string
& xpath
) OVERRIDE
{}
212 virtual void AddMessageHandler(
213 content::WebUIMessageHandler
* handler
) OVERRIDE
{}
214 virtual void RegisterMessageCallback(
215 const std::string
& message
,
216 const MessageCallback
& callback
) OVERRIDE
{}
217 virtual void ProcessWebUIMessage(const GURL
& source_url
,
218 const std::string
& message
,
219 const base::ListValue
& args
) OVERRIDE
{}
220 virtual void CallJavascriptFunction(const std::string
& function_name
,
221 const base::Value
& arg1
,
222 const base::Value
& arg2
,
223 const base::Value
& arg3
) OVERRIDE
{}
224 virtual void CallJavascriptFunction(const std::string
& function_name
,
225 const base::Value
& arg1
,
226 const base::Value
& arg2
,
227 const base::Value
& arg3
,
228 const base::Value
& arg4
) OVERRIDE
{}
229 virtual void CallJavascriptFunction(
230 const std::string
& function_name
,
231 const std::vector
<const base::Value
*>& args
) OVERRIDE
{}
235 CallData() : arg1(NULL
), arg2(NULL
) {}
236 std::string function_name
;
240 const std::vector
<CallData
>& call_data() { return call_data_
; }
242 std::vector
<CallData
> call_data_
;
243 base::string16 temp_string_
;
246 class TestingSyncSetupHandler
: public SyncSetupHandler
{
248 TestingSyncSetupHandler(content::WebUI
* web_ui
, Profile
* profile
)
249 : SyncSetupHandler(NULL
),
253 virtual ~TestingSyncSetupHandler() {
257 virtual void FocusUI() OVERRIDE
{}
259 virtual Profile
* GetProfile() const OVERRIDE
{ return profile_
; }
261 using SyncSetupHandler::is_configuring_sync
;
264 #if !defined(OS_CHROMEOS)
265 virtual void DisplayGaiaLoginInNewTabOrWindow() OVERRIDE
{}
268 // Weak pointer to parent profile.
270 DISALLOW_COPY_AND_ASSIGN(TestingSyncSetupHandler
);
273 // The boolean parameter indicates whether the test is run with ClientOAuth
274 // or not. The test parameter is a bool: whether or not to test with/
275 // /ClientLogin enabled or not.
276 class SyncSetupHandlerTest
: public testing::Test
{
278 SyncSetupHandlerTest() : error_(GoogleServiceAuthError::NONE
) {}
279 virtual void SetUp() OVERRIDE
{
280 error_
= GoogleServiceAuthError::AuthErrorNone();
281 profile_
.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile());
283 mock_pss_
= static_cast<ProfileSyncServiceMock
*>(
284 ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
286 ProfileSyncServiceMock::BuildMockProfileSyncService
));
287 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
288 ON_CALL(*mock_pss_
, GetPassphraseType()).WillByDefault(
289 Return(syncer::IMPLICIT_PASSPHRASE
));
290 ON_CALL(*mock_pss_
, GetPassphraseTime()).WillByDefault(
291 Return(base::Time()));
292 ON_CALL(*mock_pss_
, GetExplicitPassphraseTime()).WillByDefault(
293 Return(base::Time()));
295 mock_pss_
->Initialize();
297 #if defined(OS_CHROMEOS)
298 mock_signin_
= static_cast<SigninManagerBase
*>(
299 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
300 profile_
.get(), FakeSigninManagerBase::Build
));
302 mock_signin_
= static_cast<SigninManagerBase
*>(
303 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
304 profile_
.get(), FakeSigninManager::Build
));
306 handler_
.reset(new TestingSyncSetupHandler(&web_ui_
, profile_
.get()));
309 // Setup the expectations for calls made when displaying the config page.
310 void SetDefaultExpectationsForConfigPage() {
311 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn()).
312 WillRepeatedly(Return(true));
313 EXPECT_CALL(*mock_pss_
, GetRegisteredDataTypes()).
314 WillRepeatedly(Return(GetAllTypes()));
315 EXPECT_CALL(*mock_pss_
, GetPreferredDataTypes()).
316 WillRepeatedly(Return(GetAllTypes()));
317 EXPECT_CALL(*mock_pss_
, GetActiveDataTypes()).
318 WillRepeatedly(Return(GetAllTypes()));
319 EXPECT_CALL(*mock_pss_
, EncryptEverythingEnabled()).
320 WillRepeatedly(Return(false));
323 void SetupInitializedProfileSyncService() {
324 // An initialized ProfileSyncService will have already completed sync setup
325 // and will have an initialized sync backend.
326 if (!mock_signin_
->IsInitialized()) {
327 profile_
->GetPrefs()->SetString(
328 prefs::kGoogleServicesUsername
, kTestUser
);
329 mock_signin_
->Initialize(profile_
.get(), NULL
);
331 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
332 .WillRepeatedly(Return(true));
333 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
334 .WillRepeatedly(Return(true));
335 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
336 .WillRepeatedly(Return(true));
337 EXPECT_CALL(*mock_pss_
, sync_initialized()).WillRepeatedly(Return(true));
340 void ExpectConfig() {
341 ASSERT_EQ(1U, web_ui_
.call_data().size());
342 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
343 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
345 ASSERT_TRUE(data
.arg1
->GetAsString(&page
));
346 EXPECT_EQ(page
, "configure");
350 ASSERT_EQ(1U, web_ui_
.call_data().size());
351 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
352 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
354 ASSERT_TRUE(data
.arg1
->GetAsString(&page
));
355 EXPECT_EQ(page
, "done");
358 void ExpectSpinnerAndClose() {
359 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
360 EXPECT_EQ(1U, web_ui_
.call_data().size());
361 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
362 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
365 ASSERT_TRUE(data
.arg1
->GetAsString(&page
));
366 EXPECT_EQ(page
, "spinner");
367 // Cancelling the spinner dialog will cause CloseSyncSetup().
368 handler_
->CloseSyncSetup();
370 LoginUIServiceFactory::GetForProfile(
371 profile_
.get())->current_login_ui());
374 // It's difficult to notify sync listeners when using a ProfileSyncServiceMock
375 // so this helper routine dispatches an OnStateChanged() notification to the
376 // SyncStartupTracker.
377 void NotifySyncListeners() {
378 if (handler_
->sync_startup_tracker_
)
379 handler_
->sync_startup_tracker_
->OnStateChanged();
382 content::TestBrowserThreadBundle thread_bundle_
;
383 scoped_ptr
<Profile
> profile_
;
384 ProfileSyncServiceMock
* mock_pss_
;
385 GoogleServiceAuthError error_
;
386 SigninManagerBase
* mock_signin_
;
388 scoped_ptr
<TestingSyncSetupHandler
> handler_
;
391 TEST_F(SyncSetupHandlerTest
, Basic
) {
394 #if !defined(OS_CHROMEOS)
395 TEST_F(SyncSetupHandlerTest
, DisplayBasicLogin
) {
396 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
397 .WillRepeatedly(Return(false));
398 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
399 .WillRepeatedly(Return(false));
400 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
401 .WillRepeatedly(Return(false));
402 handler_
->HandleStartSignin(NULL
);
404 // Sync setup hands off control to the gaia login tab.
406 LoginUIServiceFactory::GetForProfile(
407 profile_
.get())->current_login_ui());
409 ASSERT_FALSE(handler_
->is_configuring_sync());
411 handler_
->CloseSyncSetup();
413 LoginUIServiceFactory::GetForProfile(
414 profile_
.get())->current_login_ui());
417 TEST_F(SyncSetupHandlerTest
, ShowSyncSetupWhenNotSignedIn
) {
418 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
419 .WillRepeatedly(Return(false));
420 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
421 .WillRepeatedly(Return(false));
422 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
423 .WillRepeatedly(Return(false));
424 handler_
->HandleShowSetupUI(NULL
);
426 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
427 ASSERT_EQ(1U, web_ui_
.call_data().size());
428 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
429 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
431 ASSERT_FALSE(handler_
->is_configuring_sync());
433 LoginUIServiceFactory::GetForProfile(
434 profile_
.get())->current_login_ui());
438 // Verifies that the handler correctly handles a cancellation when
439 // it is displaying the spinner to the user.
440 TEST_F(SyncSetupHandlerTest
, DisplayConfigureWithBackendDisabledAndCancel
) {
441 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
442 .WillRepeatedly(Return(true));
443 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, kTestUser
);
444 mock_signin_
->Initialize(profile_
.get(), NULL
);
445 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
446 .WillRepeatedly(Return(true));
447 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
448 .WillRepeatedly(Return(false));
449 error_
= GoogleServiceAuthError::AuthErrorNone();
450 EXPECT_CALL(*mock_pss_
, sync_initialized()).WillRepeatedly(Return(false));
452 // We're simulating a user setting up sync, which would cause the backend to
453 // kick off initialization, but not download user data types. The sync
454 // backend will try to download control data types (e.g encryption info), but
455 // that won't finish for this test as we're simulating cancelling while the
456 // spinner is showing.
457 handler_
->HandleShowSetupUI(NULL
);
459 EXPECT_EQ(handler_
.get(),
460 LoginUIServiceFactory::GetForProfile(
461 profile_
.get())->current_login_ui());
463 ExpectSpinnerAndClose();
466 // Verifies that the handler correctly transitions from showing the spinner
467 // to showing a configuration page when sync setup completes successfully.
468 TEST_F(SyncSetupHandlerTest
,
469 DisplayConfigureWithBackendDisabledAndSyncStartupCompleted
) {
470 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
471 .WillRepeatedly(Return(true));
472 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, kTestUser
);
473 mock_signin_
->Initialize(profile_
.get(), NULL
);
474 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
475 .WillRepeatedly(Return(true));
476 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
477 .WillRepeatedly(Return(false));
478 error_
= GoogleServiceAuthError::AuthErrorNone();
479 // Sync backend is stopped initially, and will start up.
480 EXPECT_CALL(*mock_pss_
, sync_initialized())
481 .WillRepeatedly(Return(false));
482 SetDefaultExpectationsForConfigPage();
484 handler_
->OpenSyncSetup();
486 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
487 EXPECT_EQ(1U, web_ui_
.call_data().size());
489 const TestWebUI::CallData
& data0
= web_ui_
.call_data()[0];
490 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data0
.function_name
);
492 ASSERT_TRUE(data0
.arg1
->GetAsString(&page
));
493 EXPECT_EQ(page
, "spinner");
495 Mock::VerifyAndClearExpectations(mock_pss_
);
496 // Now, act as if the ProfileSyncService has started up.
497 SetDefaultExpectationsForConfigPage();
498 EXPECT_CALL(*mock_pss_
, sync_initialized())
499 .WillRepeatedly(Return(true));
500 error_
= GoogleServiceAuthError::AuthErrorNone();
501 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
502 NotifySyncListeners();
504 // We expect a second call to SyncSetupOverlay.showSyncSetupPage.
505 EXPECT_EQ(2U, web_ui_
.call_data().size());
506 const TestWebUI::CallData
& data1
= web_ui_
.call_data().back();
507 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data1
.function_name
);
508 ASSERT_TRUE(data1
.arg1
->GetAsString(&page
));
509 EXPECT_EQ(page
, "configure");
510 base::DictionaryValue
* dictionary
;
511 ASSERT_TRUE(data1
.arg2
->GetAsDictionary(&dictionary
));
512 CheckBool(dictionary
, "passphraseFailed", false);
513 CheckBool(dictionary
, "showSyncEverythingPage", false);
514 CheckBool(dictionary
, "syncAllDataTypes", true);
515 CheckBool(dictionary
, "encryptAllData", false);
516 CheckBool(dictionary
, "usePassphrase", false);
519 // Verifies the case where the user cancels after the sync backend has
520 // initialized (meaning it already transitioned from the spinner to a proper
521 // configuration page, tested by
522 // DisplayConfigureWithBackendDisabledAndSigninSuccess), but before the user
523 // before the user has continued on.
524 TEST_F(SyncSetupHandlerTest
,
525 DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess
) {
526 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
527 .WillRepeatedly(Return(true));
528 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, kTestUser
);
529 mock_signin_
->Initialize(profile_
.get(), NULL
);
530 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
531 .WillRepeatedly(Return(true));
532 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
533 .WillRepeatedly(Return(false));
534 error_
= GoogleServiceAuthError::AuthErrorNone();
535 EXPECT_CALL(*mock_pss_
, sync_initialized())
536 .WillOnce(Return(false))
537 .WillRepeatedly(Return(true));
538 SetDefaultExpectationsForConfigPage();
539 handler_
->OpenSyncSetup();
541 // It's important to tell sync the user cancelled the setup flow before we
542 // tell it we're through with the setup progress.
543 testing::InSequence seq
;
544 EXPECT_CALL(*mock_pss_
, DisableForUser());
545 EXPECT_CALL(*mock_pss_
, SetSetupInProgress(false));
547 handler_
->CloseSyncSetup();
549 LoginUIServiceFactory::GetForProfile(
550 profile_
.get())->current_login_ui());
553 TEST_F(SyncSetupHandlerTest
,
554 DisplayConfigureWithBackendDisabledAndSigninFailed
) {
555 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
556 .WillRepeatedly(Return(true));
557 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, kTestUser
);
558 mock_signin_
->Initialize(profile_
.get(), NULL
);
559 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
560 .WillRepeatedly(Return(true));
561 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
562 .WillRepeatedly(Return(false));
563 error_
= GoogleServiceAuthError::AuthErrorNone();
564 EXPECT_CALL(*mock_pss_
, sync_initialized()).WillRepeatedly(Return(false));
566 handler_
->OpenSyncSetup();
567 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
568 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
570 ASSERT_TRUE(data
.arg1
->GetAsString(&page
));
571 EXPECT_EQ(page
, "spinner");
572 Mock::VerifyAndClearExpectations(mock_pss_
);
573 error_
= GoogleServiceAuthError(
574 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
575 EXPECT_CALL(*mock_pss_
, GetAuthError()).WillRepeatedly(ReturnRef(error_
));
576 NotifySyncListeners();
578 // On failure, the dialog will be closed.
580 LoginUIServiceFactory::GetForProfile(
581 profile_
.get())->current_login_ui());
584 #if !defined(OS_CHROMEOS)
586 class SyncSetupHandlerNonCrosTest
: public SyncSetupHandlerTest
{
588 SyncSetupHandlerNonCrosTest() {}
589 virtual void SetUp() OVERRIDE
{
590 SyncSetupHandlerTest::SetUp();
591 mock_signin_
= static_cast<SigninManagerBase
*>(
592 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
593 profile_
.get(), FakeSigninManager::Build
));
597 TEST_F(SyncSetupHandlerNonCrosTest
, HandleGaiaAuthFailure
) {
598 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
599 .WillRepeatedly(Return(false));
600 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
601 .WillRepeatedly(Return(false));
602 EXPECT_CALL(*mock_pss_
, HasUnrecoverableError())
603 .WillRepeatedly(Return(false));
604 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
605 .WillRepeatedly(Return(false));
607 handler_
->OpenSyncSetup();
609 ASSERT_FALSE(handler_
->is_configuring_sync());
612 // TODO(kochi): We need equivalent tests for ChromeOS.
613 TEST_F(SyncSetupHandlerNonCrosTest
, UnrecoverableErrorInitializingSync
) {
614 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
615 .WillRepeatedly(Return(false));
616 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
617 .WillRepeatedly(Return(false));
618 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
619 .WillRepeatedly(Return(false));
621 handler_
->OpenSyncSetup();
623 ASSERT_FALSE(handler_
->is_configuring_sync());
626 TEST_F(SyncSetupHandlerNonCrosTest
, GaiaErrorInitializingSync
) {
627 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
628 .WillRepeatedly(Return(false));
629 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
630 .WillRepeatedly(Return(false));
631 EXPECT_CALL(*mock_pss_
, HasSyncSetupCompleted())
632 .WillRepeatedly(Return(false));
634 handler_
->OpenSyncSetup();
636 ASSERT_FALSE(handler_
->is_configuring_sync());
639 #endif // #if !defined(OS_CHROMEOS)
641 TEST_F(SyncSetupHandlerTest
, TestSyncEverything
) {
642 std::string args
= GetConfiguration(
643 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
644 base::ListValue list_args
;
645 list_args
.Append(new base::StringValue(args
));
646 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
647 .WillRepeatedly(Return(false));
648 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
649 .WillRepeatedly(Return(false));
650 SetupInitializedProfileSyncService();
651 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(true, _
));
652 handler_
->HandleConfigure(&list_args
);
654 // Ensure that we navigated to the "done" state since we don't need a
659 TEST_F(SyncSetupHandlerTest
, TestSyncNothing
) {
660 std::string args
= GetConfiguration(
661 NULL
, SYNC_NOTHING
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
662 base::ListValue list_args
;
663 list_args
.Append(new base::StringValue(args
));
664 EXPECT_CALL(*mock_pss_
, DisableForUser());
665 SetupInitializedProfileSyncService();
666 handler_
->HandleConfigure(&list_args
);
668 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
669 ASSERT_EQ(1U, web_ui_
.call_data().size());
670 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
671 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data
.function_name
);
674 TEST_F(SyncSetupHandlerTest
, TurnOnEncryptAll
) {
675 std::string args
= GetConfiguration(
676 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA
);
677 base::ListValue list_args
;
678 list_args
.Append(new base::StringValue(args
));
679 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
680 .WillRepeatedly(Return(false));
681 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
682 .WillRepeatedly(Return(false));
683 SetupInitializedProfileSyncService();
684 EXPECT_CALL(*mock_pss_
, EnableEncryptEverything());
685 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(true, _
));
686 handler_
->HandleConfigure(&list_args
);
688 // Ensure that we navigated to the "done" state since we don't need a
693 TEST_F(SyncSetupHandlerTest
, TestPassphraseStillRequired
) {
694 std::string args
= GetConfiguration(
695 NULL
, SYNC_ALL_DATA
, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS
);
696 base::ListValue list_args
;
697 list_args
.Append(new base::StringValue(args
));
698 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
699 .WillRepeatedly(Return(true));
700 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
701 .WillRepeatedly(Return(true));
702 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
703 .WillRepeatedly(Return(false));
704 SetupInitializedProfileSyncService();
705 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
706 SetDefaultExpectationsForConfigPage();
708 // We should navigate back to the configure page since we need a passphrase.
709 handler_
->HandleConfigure(&list_args
);
714 TEST_F(SyncSetupHandlerTest
, SuccessfullySetPassphrase
) {
715 base::DictionaryValue dict
;
716 dict
.SetBoolean("isGooglePassphrase", true);
717 std::string args
= GetConfiguration(&dict
,
722 base::ListValue list_args
;
723 list_args
.Append(new base::StringValue(args
));
724 // Act as if an encryption passphrase is required the first time, then never
726 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired()).WillOnce(Return(true));
727 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
728 .WillRepeatedly(Return(false));
729 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
730 .WillRepeatedly(Return(false));
731 SetupInitializedProfileSyncService();
732 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
733 EXPECT_CALL(*mock_pss_
, SetDecryptionPassphrase("gaiaPassphrase")).
734 WillOnce(Return(true));
736 handler_
->HandleConfigure(&list_args
);
737 // We should navigate to "done" page since we finished configuring.
741 TEST_F(SyncSetupHandlerTest
, SelectCustomEncryption
) {
742 base::DictionaryValue dict
;
743 dict
.SetBoolean("isGooglePassphrase", false);
744 std::string args
= GetConfiguration(&dict
,
749 base::ListValue list_args
;
750 list_args
.Append(new base::StringValue(args
));
751 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
752 .WillRepeatedly(Return(false));
753 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
754 .WillRepeatedly(Return(false));
755 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
756 .WillRepeatedly(Return(false));
757 SetupInitializedProfileSyncService();
758 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
759 EXPECT_CALL(*mock_pss_
,
760 SetEncryptionPassphrase("custom_passphrase",
761 ProfileSyncService::EXPLICIT
));
763 handler_
->HandleConfigure(&list_args
);
764 // We should navigate to "done" page since we finished configuring.
768 TEST_F(SyncSetupHandlerTest
, UnsuccessfullySetPassphrase
) {
769 base::DictionaryValue dict
;
770 dict
.SetBoolean("isGooglePassphrase", true);
771 std::string args
= GetConfiguration(&dict
,
774 "invalid_passphrase",
776 base::ListValue list_args
;
777 list_args
.Append(new base::StringValue(args
));
778 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
779 .WillRepeatedly(Return(true));
780 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
781 .WillRepeatedly(Return(true));
782 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
783 .WillRepeatedly(Return(false));
784 SetupInitializedProfileSyncService();
785 EXPECT_CALL(*mock_pss_
, OnUserChoseDatatypes(_
, _
));
786 EXPECT_CALL(*mock_pss_
, SetDecryptionPassphrase("invalid_passphrase")).
787 WillOnce(Return(false));
789 SetDefaultExpectationsForConfigPage();
790 // We should navigate back to the configure page since we need a passphrase.
791 handler_
->HandleConfigure(&list_args
);
795 // Make sure we display an error message to the user due to the failed
797 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
798 base::DictionaryValue
* dictionary
;
799 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
800 CheckBool(dictionary
, "passphraseFailed", true);
803 // Walks through each user selectable type, and tries to sync just that single
805 TEST_F(SyncSetupHandlerTest
, TestSyncIndividualTypes
) {
806 syncer::ModelTypeSet user_selectable_types
= GetAllTypes();
807 syncer::ModelTypeSet::Iterator it
;
808 for (it
= user_selectable_types
.First(); it
.Good(); it
.Inc()) {
809 syncer::ModelTypeSet type_to_set
;
810 type_to_set
.Put(it
.Get());
811 std::string args
= GetConfiguration(NULL
,
816 base::ListValue list_args
;
817 list_args
.Append(new base::StringValue(args
));
818 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
819 .WillRepeatedly(Return(false));
820 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
821 .WillRepeatedly(Return(false));
822 SetupInitializedProfileSyncService();
823 EXPECT_CALL(*mock_pss_
,
824 OnUserChoseDatatypes(false, ModelTypeSetMatches(type_to_set
)));
825 handler_
->HandleConfigure(&list_args
);
828 Mock::VerifyAndClearExpectations(mock_pss_
);
829 web_ui_
.ClearTrackedCalls();
833 TEST_F(SyncSetupHandlerTest
, TestSyncAllManually
) {
834 std::string args
= GetConfiguration(NULL
,
839 base::ListValue list_args
;
840 list_args
.Append(new base::StringValue(args
));
841 EXPECT_CALL(*mock_pss_
, IsPassphraseRequiredForDecryption())
842 .WillRepeatedly(Return(false));
843 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
844 .WillRepeatedly(Return(false));
845 SetupInitializedProfileSyncService();
846 EXPECT_CALL(*mock_pss_
,
847 OnUserChoseDatatypes(false, ModelTypeSetMatches(GetAllTypes())));
848 handler_
->HandleConfigure(&list_args
);
853 TEST_F(SyncSetupHandlerTest
, ShowSyncSetup
) {
854 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
855 .WillRepeatedly(Return(false));
856 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
857 .WillRepeatedly(Return(false));
858 SetupInitializedProfileSyncService();
859 // This should display the sync setup dialog (not login).
860 SetDefaultExpectationsForConfigPage();
861 handler_
->OpenSyncSetup();
866 // We do not display signin on chromeos in the case of auth error.
867 TEST_F(SyncSetupHandlerTest
, ShowSigninOnAuthError
) {
868 // Initialize the system to a signed in state, but with an auth error.
869 error_
= GoogleServiceAuthError(
870 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
872 SetupInitializedProfileSyncService();
873 mock_signin_
->SetAuthenticatedUsername(kTestUser
);
874 FakeAuthStatusProvider
provider(
875 SigninGlobalError::GetForProfile(profile_
.get()));
876 provider
.SetAuthError(kTestUser
, error_
);
877 EXPECT_CALL(*mock_pss_
, IsSyncEnabledAndLoggedIn())
878 .WillRepeatedly(Return(true));
879 EXPECT_CALL(*mock_pss_
, IsOAuthRefreshTokenAvailable())
880 .WillRepeatedly(Return(true));
881 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
882 .WillRepeatedly(Return(false));
883 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
884 .WillRepeatedly(Return(false));
885 EXPECT_CALL(*mock_pss_
, sync_initialized()).WillRepeatedly(Return(false));
887 #if defined(OS_CHROMEOS)
888 // On ChromeOS, auth errors are ignored - instead we just try to start the
889 // sync backend (which will fail due to the auth error). This should only
890 // happen if the user manually navigates to chrome://settings/syncSetup -
891 // clicking on the button in the UI will sign the user out rather than
892 // displaying a spinner. Should be no visible UI on ChromeOS in this case.
893 EXPECT_EQ(NULL
, LoginUIServiceFactory::GetForProfile(
894 profile_
.get())->current_login_ui());
897 // On ChromeOS, this should display the spinner while we try to startup the
898 // sync backend, and on desktop this displays the login dialog.
899 handler_
->OpenSyncSetup();
901 // Sync setup is closed when re-auth is in progress.
903 LoginUIServiceFactory::GetForProfile(
904 profile_
.get())->current_login_ui());
906 ASSERT_FALSE(handler_
->is_configuring_sync());
910 TEST_F(SyncSetupHandlerTest
, ShowSetupSyncEverything
) {
911 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
912 .WillRepeatedly(Return(false));
913 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
914 .WillRepeatedly(Return(false));
915 SetupInitializedProfileSyncService();
916 SetDefaultExpectationsForConfigPage();
917 // This should display the sync setup dialog (not login).
918 handler_
->OpenSyncSetup();
921 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
922 base::DictionaryValue
* dictionary
;
923 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
924 CheckBool(dictionary
, "showSyncEverythingPage", false);
925 CheckBool(dictionary
, "syncAllDataTypes", true);
926 CheckBool(dictionary
, "appsRegistered", true);
927 CheckBool(dictionary
, "autofillRegistered", true);
928 CheckBool(dictionary
, "bookmarksRegistered", true);
929 CheckBool(dictionary
, "extensionsRegistered", true);
930 CheckBool(dictionary
, "passwordsRegistered", true);
931 CheckBool(dictionary
, "preferencesRegistered", true);
932 CheckBool(dictionary
, "tabsRegistered", true);
933 CheckBool(dictionary
, "themesRegistered", true);
934 CheckBool(dictionary
, "typedUrlsRegistered", true);
935 CheckBool(dictionary
, "showPassphrase", false);
936 CheckBool(dictionary
, "usePassphrase", false);
937 CheckBool(dictionary
, "passphraseFailed", false);
938 CheckBool(dictionary
, "encryptAllData", false);
939 CheckConfigDataTypeArguments(dictionary
, SYNC_ALL_DATA
, GetAllTypes());
942 TEST_F(SyncSetupHandlerTest
, ShowSetupManuallySyncAll
) {
943 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
944 .WillRepeatedly(Return(false));
945 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
946 .WillRepeatedly(Return(false));
947 SetupInitializedProfileSyncService();
948 browser_sync::SyncPrefs
sync_prefs(profile_
->GetPrefs());
949 sync_prefs
.SetKeepEverythingSynced(false);
950 SetDefaultExpectationsForConfigPage();
951 // This should display the sync setup dialog (not login).
952 handler_
->OpenSyncSetup();
955 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
956 base::DictionaryValue
* dictionary
;
957 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
958 CheckConfigDataTypeArguments(dictionary
, CHOOSE_WHAT_TO_SYNC
, GetAllTypes());
961 TEST_F(SyncSetupHandlerTest
, ShowSetupSyncForAllTypesIndividually
) {
962 syncer::ModelTypeSet user_selectable_types
= GetAllTypes();
963 syncer::ModelTypeSet::Iterator it
;
964 for (it
= user_selectable_types
.First(); it
.Good(); it
.Inc()) {
965 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
966 .WillRepeatedly(Return(false));
967 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
968 .WillRepeatedly(Return(false));
969 SetupInitializedProfileSyncService();
970 browser_sync::SyncPrefs
sync_prefs(profile_
->GetPrefs());
971 sync_prefs
.SetKeepEverythingSynced(false);
972 SetDefaultExpectationsForConfigPage();
973 syncer::ModelTypeSet types
;
975 EXPECT_CALL(*mock_pss_
, GetPreferredDataTypes()).
976 WillRepeatedly(Return(types
));
978 // This should display the sync setup dialog (not login).
979 handler_
->OpenSyncSetup();
982 // Close the config overlay.
983 LoginUIServiceFactory::GetForProfile(profile_
.get())->LoginUIClosed(
985 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
986 base::DictionaryValue
* dictionary
;
987 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
988 CheckConfigDataTypeArguments(dictionary
, CHOOSE_WHAT_TO_SYNC
, types
);
989 Mock::VerifyAndClearExpectations(mock_pss_
);
990 // Clean up so we can loop back to display the dialog again.
991 web_ui_
.ClearTrackedCalls();
995 TEST_F(SyncSetupHandlerTest
, ShowSetupGaiaPassphraseRequired
) {
996 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
997 .WillRepeatedly(Return(true));
998 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
999 .WillRepeatedly(Return(false));
1000 SetupInitializedProfileSyncService();
1001 SetDefaultExpectationsForConfigPage();
1003 // This should display the sync setup dialog (not login).
1004 handler_
->OpenSyncSetup();
1007 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
1008 base::DictionaryValue
* dictionary
;
1009 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
1010 CheckBool(dictionary
, "showPassphrase", true);
1011 CheckBool(dictionary
, "usePassphrase", false);
1012 CheckBool(dictionary
, "passphraseFailed", false);
1015 TEST_F(SyncSetupHandlerTest
, ShowSetupCustomPassphraseRequired
) {
1016 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
1017 .WillRepeatedly(Return(true));
1018 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
1019 .WillRepeatedly(Return(true));
1020 EXPECT_CALL(*mock_pss_
, GetPassphraseType())
1021 .WillRepeatedly(Return(syncer::CUSTOM_PASSPHRASE
));
1022 SetupInitializedProfileSyncService();
1023 SetDefaultExpectationsForConfigPage();
1025 // This should display the sync setup dialog (not login).
1026 handler_
->OpenSyncSetup();
1029 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
1030 base::DictionaryValue
* dictionary
;
1031 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
1032 CheckBool(dictionary
, "showPassphrase", true);
1033 CheckBool(dictionary
, "usePassphrase", true);
1034 CheckBool(dictionary
, "passphraseFailed", false);
1037 TEST_F(SyncSetupHandlerTest
, ShowSetupEncryptAll
) {
1038 EXPECT_CALL(*mock_pss_
, IsPassphraseRequired())
1039 .WillRepeatedly(Return(false));
1040 EXPECT_CALL(*mock_pss_
, IsUsingSecondaryPassphrase())
1041 .WillRepeatedly(Return(false));
1042 SetupInitializedProfileSyncService();
1043 SetDefaultExpectationsForConfigPage();
1044 EXPECT_CALL(*mock_pss_
, EncryptEverythingEnabled()).
1045 WillRepeatedly(Return(true));
1047 // This should display the sync setup dialog (not login).
1048 handler_
->OpenSyncSetup();
1051 const TestWebUI::CallData
& data
= web_ui_
.call_data()[0];
1052 base::DictionaryValue
* dictionary
;
1053 ASSERT_TRUE(data
.arg2
->GetAsDictionary(&dictionary
));
1054 CheckBool(dictionary
, "encryptAllData", true);