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.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service_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/profile_oauth2_token_service.h"
29 #include "components/signin/core/browser/signin_manager.h"
30 #include "components/sync_driver/sync_prefs.h"
31 #include "content/public/browser/web_ui.h"
32 #include "content/public/test/test_browser_thread.h"
33 #include "content/public/test/test_browser_thread_bundle.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(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 // Test instance of WebUI that tracks the data passed to
151 // CallJavascriptFunction().
152 class TestWebUI : public content::WebUI {
154 ~TestWebUI() override { ClearTrackedCalls(); }
156 void ClearTrackedCalls() {
157 // Manually free the arguments stored in CallData, since there's no good
158 // way to use a self-freeing reference like scoped_ptr in a std::vector.
159 for (std::vector<CallData>::iterator i = call_data_.begin();
160 i != call_data_.end();
168 void CallJavascriptFunction(const std::string& function_name) override {
169 call_data_.push_back(CallData());
170 call_data_.back().function_name = function_name;
173 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 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 content::WebContents* GetWebContents() const override { return NULL; }
190 content::WebUIController* GetController() const override { return NULL; }
191 void SetController(content::WebUIController* controller) override {}
192 float GetDeviceScaleFactor() const override { return 1.0f; }
193 const base::string16& GetOverriddenTitle() const override {
196 void OverrideTitle(const base::string16& title) override {}
197 ui::PageTransition GetLinkTransitionType() const override {
198 return ui::PAGE_TRANSITION_LINK;
200 void SetLinkTransitionType(ui::PageTransition type) override {}
201 int GetBindings() const override { return 0; }
202 void SetBindings(int bindings) override {}
203 void OverrideJavaScriptFrame(const std::string& frame_name) override {}
204 void AddMessageHandler(content::WebUIMessageHandler* handler) override {}
205 void RegisterMessageCallback(const std::string& message,
206 const MessageCallback& callback) override {}
207 void ProcessWebUIMessage(const GURL& source_url,
208 const std::string& message,
209 const base::ListValue& args) override {}
210 void CallJavascriptFunction(const std::string& function_name,
211 const base::Value& arg1,
212 const base::Value& arg2,
213 const base::Value& arg3) override {}
214 void CallJavascriptFunction(const std::string& function_name,
215 const base::Value& arg1,
216 const base::Value& arg2,
217 const base::Value& arg3,
218 const base::Value& arg4) override {}
219 void CallJavascriptFunction(
220 const std::string& function_name,
221 const std::vector<const base::Value*>& args) override {}
225 CallData() : arg1(NULL), arg2(NULL) {}
226 std::string function_name;
230 const std::vector<CallData>& call_data() { return call_data_; }
232 std::vector<CallData> call_data_;
233 base::string16 temp_string_;
236 class TestingSyncSetupHandler : public SyncSetupHandler {
238 TestingSyncSetupHandler(content::WebUI* web_ui, Profile* profile)
239 : SyncSetupHandler(NULL),
243 ~TestingSyncSetupHandler() override { set_web_ui(NULL); }
245 void FocusUI() override {}
247 Profile* GetProfile() const override { return profile_; }
249 using SyncSetupHandler::is_configuring_sync;
252 #if !defined(OS_CHROMEOS)
253 void DisplayGaiaLoginInNewTabOrWindow() override {}
256 // Weak pointer to parent profile.
258 DISALLOW_COPY_AND_ASSIGN(TestingSyncSetupHandler);
261 // The boolean parameter indicates whether the test is run with ClientOAuth
262 // or not. The test parameter is a bool: whether or not to test with/
263 // /ClientLogin enabled or not.
264 class SyncSetupHandlerTest : public testing::Test {
266 SyncSetupHandlerTest() : error_(GoogleServiceAuthError::NONE) {}
267 void SetUp() override {
268 error_ = GoogleServiceAuthError::AuthErrorNone();
270 TestingProfile::Builder builder;
271 builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
272 FakeSigninManagerBase::Build);
273 profile_ = builder.Build();
276 mock_signin_ = static_cast<SigninManagerBase*>(
277 SigninManagerFactory::GetForProfile(profile_.get()));
278 std::string username = GetTestUser();
279 if (!username.empty()) {
280 mock_signin_->SetAuthenticatedUsername(username);
281 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
285 mock_pss_ = static_cast<ProfileSyncServiceMock*>(
286 ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
288 ProfileSyncServiceMock::BuildMockProfileSyncService));
289 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
290 ON_CALL(*mock_pss_, GetPassphraseType()).WillByDefault(
291 Return(syncer::IMPLICIT_PASSPHRASE));
292 ON_CALL(*mock_pss_, GetPassphraseTime()).WillByDefault(
293 Return(base::Time()));
294 ON_CALL(*mock_pss_, GetExplicitPassphraseTime()).WillByDefault(
295 Return(base::Time()));
296 ON_CALL(*mock_pss_, GetRegisteredDataTypes())
297 .WillByDefault(Return(syncer::ModelTypeSet()));
299 mock_pss_->Initialize();
301 handler_.reset(new TestingSyncSetupHandler(&web_ui_, profile_.get()));
304 // Setup the expectations for calls made when displaying the config page.
305 void SetDefaultExpectationsForConfigPage() {
306 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn()).
307 WillRepeatedly(Return(true));
308 EXPECT_CALL(*mock_pss_, GetRegisteredDataTypes()).
309 WillRepeatedly(Return(GetAllTypes()));
310 EXPECT_CALL(*mock_pss_, GetPreferredDataTypes()).
311 WillRepeatedly(Return(GetAllTypes()));
312 EXPECT_CALL(*mock_pss_, GetActiveDataTypes()).
313 WillRepeatedly(Return(GetAllTypes()));
314 EXPECT_CALL(*mock_pss_, EncryptEverythingAllowed()).
315 WillRepeatedly(Return(true));
316 EXPECT_CALL(*mock_pss_, EncryptEverythingEnabled()).
317 WillRepeatedly(Return(false));
320 void SetupInitializedProfileSyncService() {
321 // An initialized ProfileSyncService will have already completed sync setup
322 // and will have an initialized sync backend.
323 ASSERT_TRUE(mock_signin_->IsInitialized());
324 EXPECT_CALL(*mock_pss_, backend_initialized()).WillRepeatedly(Return(true));
327 void ExpectConfig() {
328 ASSERT_EQ(1U, web_ui_.call_data().size());
329 const TestWebUI::CallData& data = web_ui_.call_data()[0];
330 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
332 ASSERT_TRUE(data.arg1->GetAsString(&page));
333 EXPECT_EQ(page, "configure");
337 ASSERT_EQ(1U, web_ui_.call_data().size());
338 const TestWebUI::CallData& data = web_ui_.call_data()[0];
339 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
341 ASSERT_TRUE(data.arg1->GetAsString(&page));
342 EXPECT_EQ(page, "done");
345 void ExpectSpinnerAndClose() {
346 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
347 EXPECT_EQ(1U, web_ui_.call_data().size());
348 const TestWebUI::CallData& data = web_ui_.call_data()[0];
349 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
352 ASSERT_TRUE(data.arg1->GetAsString(&page));
353 EXPECT_EQ(page, "spinner");
354 // Cancelling the spinner dialog will cause CloseSyncSetup().
355 handler_->CloseSyncSetup();
357 LoginUIServiceFactory::GetForProfile(
358 profile_.get())->current_login_ui());
361 // It's difficult to notify sync listeners when using a ProfileSyncServiceMock
362 // so this helper routine dispatches an OnStateChanged() notification to the
363 // SyncStartupTracker.
364 void NotifySyncListeners() {
365 if (handler_->sync_startup_tracker_)
366 handler_->sync_startup_tracker_->OnStateChanged();
369 virtual std::string GetTestUser() {
370 return std::string(kTestUser);
373 content::TestBrowserThreadBundle thread_bundle_;
374 scoped_ptr<Profile> profile_;
375 ProfileSyncServiceMock* mock_pss_;
376 GoogleServiceAuthError error_;
377 SigninManagerBase* mock_signin_;
379 scoped_ptr<TestingSyncSetupHandler> handler_;
382 class SyncSetupHandlerFirstSigninTest : public SyncSetupHandlerTest {
383 std::string GetTestUser() override { return std::string(); }
386 TEST_F(SyncSetupHandlerTest, Basic) {
389 #if !defined(OS_CHROMEOS)
390 TEST_F(SyncSetupHandlerFirstSigninTest, DisplayBasicLogin) {
391 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
392 .WillRepeatedly(Return(false));
393 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
394 .WillRepeatedly(Return(false));
395 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
396 .WillRepeatedly(Return(false));
397 // Ensure that the user is not signed in before calling |HandleStartSignin()|.
398 SigninManager* manager = static_cast<SigninManager*>(mock_signin_);
399 manager->SignOut(signin_metrics::SIGNOUT_TEST);
400 handler_->HandleStartSignin(NULL);
402 // Sync setup hands off control to the gaia login tab.
404 LoginUIServiceFactory::GetForProfile(
405 profile_.get())->current_login_ui());
407 ASSERT_FALSE(handler_->is_configuring_sync());
409 handler_->CloseSyncSetup();
411 LoginUIServiceFactory::GetForProfile(
412 profile_.get())->current_login_ui());
415 TEST_F(SyncSetupHandlerTest, ShowSyncSetupWhenNotSignedIn) {
416 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
417 .WillRepeatedly(Return(false));
418 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
419 .WillRepeatedly(Return(false));
420 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
421 .WillRepeatedly(Return(false));
422 handler_->HandleShowSetupUI(NULL);
424 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
425 ASSERT_EQ(1U, web_ui_.call_data().size());
426 const TestWebUI::CallData& data = web_ui_.call_data()[0];
427 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
429 ASSERT_FALSE(handler_->is_configuring_sync());
431 LoginUIServiceFactory::GetForProfile(
432 profile_.get())->current_login_ui());
434 #endif // !defined(OS_CHROMEOS)
436 // Verifies that the sync setup is terminated correctly when the
438 TEST_F(SyncSetupHandlerTest, HandleSetupUIWhenSyncDisabled) {
439 EXPECT_CALL(*mock_pss_, IsManaged()).WillRepeatedly(Return(true));
440 handler_->HandleShowSetupUI(NULL);
442 // Sync setup is closed when sync is disabled.
444 LoginUIServiceFactory::GetForProfile(
445 profile_.get())->current_login_ui());
446 ASSERT_FALSE(handler_->is_configuring_sync());
449 // Verifies that the handler correctly handles a cancellation when
450 // it is displaying the spinner to the user.
451 TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndCancel) {
452 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
453 .WillRepeatedly(Return(true));
454 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
455 .WillRepeatedly(Return(true));
456 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
457 .WillRepeatedly(Return(false));
458 error_ = GoogleServiceAuthError::AuthErrorNone();
459 EXPECT_CALL(*mock_pss_, backend_initialized()).WillRepeatedly(Return(false));
461 // We're simulating a user setting up sync, which would cause the backend to
462 // kick off initialization, but not download user data types. The sync
463 // backend will try to download control data types (e.g encryption info), but
464 // that won't finish for this test as we're simulating cancelling while the
465 // spinner is showing.
466 handler_->HandleShowSetupUI(NULL);
468 EXPECT_EQ(handler_.get(),
469 LoginUIServiceFactory::GetForProfile(
470 profile_.get())->current_login_ui());
472 ExpectSpinnerAndClose();
475 // Verifies that the handler correctly transitions from showing the spinner
476 // to showing a configuration page when sync setup completes successfully.
477 TEST_F(SyncSetupHandlerTest,
478 DisplayConfigureWithBackendDisabledAndSyncStartupCompleted) {
479 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
480 .WillRepeatedly(Return(true));
481 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
482 .WillRepeatedly(Return(true));
483 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
484 .WillRepeatedly(Return(false));
485 error_ = GoogleServiceAuthError::AuthErrorNone();
486 // Sync backend is stopped initially, and will start up.
487 EXPECT_CALL(*mock_pss_, backend_initialized())
488 .WillRepeatedly(Return(false));
489 SetDefaultExpectationsForConfigPage();
491 handler_->OpenSyncSetup();
493 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
494 EXPECT_EQ(1U, web_ui_.call_data().size());
496 const TestWebUI::CallData& data0 = web_ui_.call_data()[0];
497 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data0.function_name);
499 ASSERT_TRUE(data0.arg1->GetAsString(&page));
500 EXPECT_EQ(page, "spinner");
502 Mock::VerifyAndClearExpectations(mock_pss_);
503 // Now, act as if the ProfileSyncService has started up.
504 SetDefaultExpectationsForConfigPage();
505 EXPECT_CALL(*mock_pss_, backend_initialized())
506 .WillRepeatedly(Return(true));
507 error_ = GoogleServiceAuthError::AuthErrorNone();
508 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
509 NotifySyncListeners();
511 // We expect a second call to SyncSetupOverlay.showSyncSetupPage.
512 EXPECT_EQ(2U, web_ui_.call_data().size());
513 const TestWebUI::CallData& data1 = web_ui_.call_data().back();
514 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data1.function_name);
515 ASSERT_TRUE(data1.arg1->GetAsString(&page));
516 EXPECT_EQ(page, "configure");
517 base::DictionaryValue* dictionary;
518 ASSERT_TRUE(data1.arg2->GetAsDictionary(&dictionary));
519 CheckBool(dictionary, "passphraseFailed", false);
520 CheckBool(dictionary, "showSyncEverythingPage", false);
521 CheckBool(dictionary, "syncAllDataTypes", true);
522 CheckBool(dictionary, "encryptAllDataAllowed", true);
523 CheckBool(dictionary, "encryptAllData", false);
524 CheckBool(dictionary, "usePassphrase", false);
527 // Verifies the case where the user cancels after the sync backend has
528 // initialized (meaning it already transitioned from the spinner to a proper
529 // configuration page, tested by
530 // DisplayConfigureWithBackendDisabledAndSigninSuccess), but before the user
531 // before the user has continued on.
532 TEST_F(SyncSetupHandlerTest,
533 DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess) {
534 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
535 .WillRepeatedly(Return(true));
536 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
537 .WillRepeatedly(Return(true));
538 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
539 .WillRepeatedly(Return(false));
540 error_ = GoogleServiceAuthError::AuthErrorNone();
541 EXPECT_CALL(*mock_pss_, backend_initialized())
542 .WillOnce(Return(false))
543 .WillRepeatedly(Return(true));
544 SetDefaultExpectationsForConfigPage();
545 handler_->OpenSyncSetup();
547 // It's important to tell sync the user cancelled the setup flow before we
548 // tell it we're through with the setup progress.
549 testing::InSequence seq;
550 EXPECT_CALL(*mock_pss_, DisableForUser());
551 EXPECT_CALL(*mock_pss_, SetSetupInProgress(false));
553 handler_->CloseSyncSetup();
555 LoginUIServiceFactory::GetForProfile(
556 profile_.get())->current_login_ui());
559 TEST_F(SyncSetupHandlerTest,
560 DisplayConfigureWithBackendDisabledAndSigninFailed) {
561 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
562 .WillRepeatedly(Return(true));
563 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
564 .WillRepeatedly(Return(true));
565 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
566 .WillRepeatedly(Return(false));
567 error_ = GoogleServiceAuthError::AuthErrorNone();
568 EXPECT_CALL(*mock_pss_, backend_initialized()).WillRepeatedly(Return(false));
570 handler_->OpenSyncSetup();
571 const TestWebUI::CallData& data = web_ui_.call_data()[0];
572 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
574 ASSERT_TRUE(data.arg1->GetAsString(&page));
575 EXPECT_EQ(page, "spinner");
576 Mock::VerifyAndClearExpectations(mock_pss_);
577 error_ = GoogleServiceAuthError(
578 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
579 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
580 NotifySyncListeners();
582 // On failure, the dialog will be closed.
584 LoginUIServiceFactory::GetForProfile(
585 profile_.get())->current_login_ui());
588 #if !defined(OS_CHROMEOS)
590 class SyncSetupHandlerNonCrosTest : public SyncSetupHandlerTest {
592 SyncSetupHandlerNonCrosTest() {}
595 TEST_F(SyncSetupHandlerNonCrosTest, HandleGaiaAuthFailure) {
596 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
597 .WillRepeatedly(Return(false));
598 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
599 .WillRepeatedly(Return(false));
600 EXPECT_CALL(*mock_pss_, HasUnrecoverableError())
601 .WillRepeatedly(Return(false));
602 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
603 .WillRepeatedly(Return(false));
605 handler_->OpenSyncSetup();
607 ASSERT_FALSE(handler_->is_configuring_sync());
610 // TODO(kochi): We need equivalent tests for ChromeOS.
611 TEST_F(SyncSetupHandlerNonCrosTest, UnrecoverableErrorInitializingSync) {
612 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
613 .WillRepeatedly(Return(false));
614 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
615 .WillRepeatedly(Return(false));
616 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
617 .WillRepeatedly(Return(false));
619 handler_->OpenSyncSetup();
621 ASSERT_FALSE(handler_->is_configuring_sync());
624 TEST_F(SyncSetupHandlerNonCrosTest, GaiaErrorInitializingSync) {
625 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
626 .WillRepeatedly(Return(false));
627 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
628 .WillRepeatedly(Return(false));
629 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
630 .WillRepeatedly(Return(false));
632 handler_->OpenSyncSetup();
634 ASSERT_FALSE(handler_->is_configuring_sync());
637 #endif // #if !defined(OS_CHROMEOS)
639 TEST_F(SyncSetupHandlerTest, TestSyncEverything) {
640 std::string args = GetConfiguration(
641 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS);
642 base::ListValue list_args;
643 list_args.Append(new base::StringValue(args));
644 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
645 .WillRepeatedly(Return(false));
646 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
647 .WillRepeatedly(Return(false));
648 SetupInitializedProfileSyncService();
649 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
650 handler_->HandleConfigure(&list_args);
652 // Ensure that we navigated to the "done" state since we don't need a
657 TEST_F(SyncSetupHandlerTest, TestSyncNothing) {
658 std::string args = GetConfiguration(
659 NULL, SYNC_NOTHING, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS);
660 base::ListValue list_args;
661 list_args.Append(new base::StringValue(args));
662 EXPECT_CALL(*mock_pss_, DisableForUser());
663 SetupInitializedProfileSyncService();
664 handler_->HandleConfigure(&list_args);
666 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
667 ASSERT_EQ(1U, web_ui_.call_data().size());
668 const TestWebUI::CallData& data = web_ui_.call_data()[0];
669 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
672 TEST_F(SyncSetupHandlerTest, TurnOnEncryptAll) {
673 std::string args = GetConfiguration(
674 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA);
675 base::ListValue list_args;
676 list_args.Append(new base::StringValue(args));
677 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
678 .WillRepeatedly(Return(false));
679 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
680 .WillRepeatedly(Return(false));
681 EXPECT_CALL(*mock_pss_, EncryptEverythingAllowed())
682 .WillRepeatedly(Return(true));
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 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())->
876 signin_error_controller());
877 provider.SetAuthError(kTestUser, kTestUser, error_);
878 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
879 .WillRepeatedly(Return(true));
880 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
881 .WillRepeatedly(Return(true));
882 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
883 .WillRepeatedly(Return(false));
884 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
885 .WillRepeatedly(Return(false));
886 EXPECT_CALL(*mock_pss_, backend_initialized()).WillRepeatedly(Return(false));
888 #if defined(OS_CHROMEOS)
889 // On ChromeOS, auth errors are ignored - instead we just try to start the
890 // sync backend (which will fail due to the auth error). This should only
891 // happen if the user manually navigates to chrome://settings/syncSetup -
892 // clicking on the button in the UI will sign the user out rather than
893 // displaying a spinner. Should be no visible UI on ChromeOS in this case.
894 EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile(
895 profile_.get())->current_login_ui());
898 // On ChromeOS, this should display the spinner while we try to startup the
899 // sync backend, and on desktop this displays the login dialog.
900 handler_->OpenSyncSetup();
902 // Sync setup is closed when re-auth is in progress.
904 LoginUIServiceFactory::GetForProfile(
905 profile_.get())->current_login_ui());
907 ASSERT_FALSE(handler_->is_configuring_sync());
911 TEST_F(SyncSetupHandlerTest, ShowSetupSyncEverything) {
912 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
913 .WillRepeatedly(Return(false));
914 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
915 .WillRepeatedly(Return(false));
916 SetupInitializedProfileSyncService();
917 SetDefaultExpectationsForConfigPage();
918 // This should display the sync setup dialog (not login).
919 handler_->OpenSyncSetup();
922 const TestWebUI::CallData& data = web_ui_.call_data()[0];
923 base::DictionaryValue* dictionary;
924 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
925 CheckBool(dictionary, "showSyncEverythingPage", false);
926 CheckBool(dictionary, "syncAllDataTypes", true);
927 CheckBool(dictionary, "appsRegistered", true);
928 CheckBool(dictionary, "autofillRegistered", true);
929 CheckBool(dictionary, "bookmarksRegistered", true);
930 CheckBool(dictionary, "extensionsRegistered", true);
931 CheckBool(dictionary, "passwordsRegistered", true);
932 CheckBool(dictionary, "preferencesRegistered", true);
933 CheckBool(dictionary, "wifiCredentialsRegistered", true);
934 CheckBool(dictionary, "tabsRegistered", true);
935 CheckBool(dictionary, "themesRegistered", true);
936 CheckBool(dictionary, "typedUrlsRegistered", true);
937 CheckBool(dictionary, "showPassphrase", false);
938 CheckBool(dictionary, "usePassphrase", false);
939 CheckBool(dictionary, "passphraseFailed", false);
940 CheckBool(dictionary, "encryptAllData", false);
941 CheckConfigDataTypeArguments(dictionary, SYNC_ALL_DATA, GetAllTypes());
944 TEST_F(SyncSetupHandlerTest, ShowSetupManuallySyncAll) {
945 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
946 .WillRepeatedly(Return(false));
947 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
948 .WillRepeatedly(Return(false));
949 SetupInitializedProfileSyncService();
950 sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
951 sync_prefs.SetKeepEverythingSynced(false);
952 SetDefaultExpectationsForConfigPage();
953 // This should display the sync setup dialog (not login).
954 handler_->OpenSyncSetup();
957 const TestWebUI::CallData& data = web_ui_.call_data()[0];
958 base::DictionaryValue* dictionary;
959 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
960 CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, GetAllTypes());
963 TEST_F(SyncSetupHandlerTest, ShowSetupSyncForAllTypesIndividually) {
964 syncer::ModelTypeSet user_selectable_types = GetAllTypes();
965 syncer::ModelTypeSet::Iterator it;
966 for (it = user_selectable_types.First(); it.Good(); it.Inc()) {
967 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
968 .WillRepeatedly(Return(false));
969 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
970 .WillRepeatedly(Return(false));
971 SetupInitializedProfileSyncService();
972 sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
973 sync_prefs.SetKeepEverythingSynced(false);
974 SetDefaultExpectationsForConfigPage();
975 syncer::ModelTypeSet types;
977 EXPECT_CALL(*mock_pss_, GetPreferredDataTypes()).
978 WillRepeatedly(Return(types));
980 // This should display the sync setup dialog (not login).
981 handler_->OpenSyncSetup();
984 // Close the config overlay.
985 LoginUIServiceFactory::GetForProfile(profile_.get())->LoginUIClosed(
987 const TestWebUI::CallData& data = web_ui_.call_data()[0];
988 base::DictionaryValue* dictionary;
989 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
990 CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, types);
991 Mock::VerifyAndClearExpectations(mock_pss_);
992 // Clean up so we can loop back to display the dialog again.
993 web_ui_.ClearTrackedCalls();
997 TEST_F(SyncSetupHandlerTest, ShowSetupGaiaPassphraseRequired) {
998 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
999 .WillRepeatedly(Return(true));
1000 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1001 .WillRepeatedly(Return(false));
1002 SetupInitializedProfileSyncService();
1003 SetDefaultExpectationsForConfigPage();
1005 // This should display the sync setup dialog (not login).
1006 handler_->OpenSyncSetup();
1009 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1010 base::DictionaryValue* dictionary;
1011 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1012 CheckBool(dictionary, "showPassphrase", true);
1013 CheckBool(dictionary, "usePassphrase", false);
1014 CheckBool(dictionary, "passphraseFailed", false);
1017 TEST_F(SyncSetupHandlerTest, ShowSetupCustomPassphraseRequired) {
1018 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1019 .WillRepeatedly(Return(true));
1020 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1021 .WillRepeatedly(Return(true));
1022 EXPECT_CALL(*mock_pss_, GetPassphraseType())
1023 .WillRepeatedly(Return(syncer::CUSTOM_PASSPHRASE));
1024 SetupInitializedProfileSyncService();
1025 SetDefaultExpectationsForConfigPage();
1027 // This should display the sync setup dialog (not login).
1028 handler_->OpenSyncSetup();
1031 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1032 base::DictionaryValue* dictionary;
1033 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1034 CheckBool(dictionary, "showPassphrase", true);
1035 CheckBool(dictionary, "usePassphrase", true);
1036 CheckBool(dictionary, "passphraseFailed", false);
1039 TEST_F(SyncSetupHandlerTest, ShowSetupEncryptAll) {
1040 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1041 .WillRepeatedly(Return(false));
1042 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1043 .WillRepeatedly(Return(false));
1044 SetupInitializedProfileSyncService();
1045 SetDefaultExpectationsForConfigPage();
1046 EXPECT_CALL(*mock_pss_, EncryptEverythingEnabled()).
1047 WillRepeatedly(Return(true));
1049 // This should display the sync setup dialog (not login).
1050 handler_->OpenSyncSetup();
1053 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1054 base::DictionaryValue* dictionary;
1055 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1056 CheckBool(dictionary, "encryptAllData", true);
1059 TEST_F(SyncSetupHandlerTest, ShowSetupEncryptAllDisallowed) {
1060 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1061 .WillRepeatedly(Return(false));
1062 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1063 .WillRepeatedly(Return(false));
1064 SetupInitializedProfileSyncService();
1065 SetDefaultExpectationsForConfigPage();
1066 EXPECT_CALL(*mock_pss_, EncryptEverythingAllowed()).
1067 WillRepeatedly(Return(false));
1069 // This should display the sync setup dialog (not login).
1070 handler_->OpenSyncSetup();
1073 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1074 base::DictionaryValue* dictionary;
1075 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1076 CheckBool(dictionary, "encryptAllData", false);
1077 CheckBool(dictionary, "encryptAllDataAllowed", false);
1080 TEST_F(SyncSetupHandlerTest, TurnOnEncryptAllDisallowed) {
1081 std::string args = GetConfiguration(
1082 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA);
1083 base::ListValue list_args;
1084 list_args.Append(new base::StringValue(args));
1085 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
1086 .WillRepeatedly(Return(false));
1087 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1088 .WillRepeatedly(Return(false));
1089 SetupInitializedProfileSyncService();
1090 EXPECT_CALL(*mock_pss_, EncryptEverythingAllowed()).
1091 WillRepeatedly(Return(false));
1092 EXPECT_CALL(*mock_pss_, EnableEncryptEverything()).Times(0);
1093 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
1094 handler_->HandleConfigure(&list_args);
1096 // Ensure that we navigated to the "done" state since we don't need a