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_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 "grit/generated_resources.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/layout.h"
40 using ::testing::Mock;
41 using ::testing::Return;
42 using ::testing::ReturnRef;
43 using ::testing::Values;
45 typedef GoogleServiceAuthError AuthError;
49 MATCHER_P(ModelTypeSetMatches, value, "") { return arg.Equals(value); }
51 const char kTestUser[] = "chrome.p13n.test@gmail.com";
53 // Returns a ModelTypeSet with all user selectable types set.
54 syncer::ModelTypeSet GetAllTypes() {
55 return syncer::UserSelectableTypes();
58 enum SyncAllDataConfig {
64 enum EncryptAllConfig {
69 // Create a json-format string with the key/value pairs appropriate for a call
70 // to HandleConfigure(). If |extra_values| is non-null, then the values from
71 // the passed dictionary are added to the json.
72 std::string GetConfiguration(const base::DictionaryValue* extra_values,
73 SyncAllDataConfig sync_all,
74 syncer::ModelTypeSet types,
75 const std::string& passphrase,
76 EncryptAllConfig encrypt_all) {
77 base::DictionaryValue result;
79 result.MergeDictionary(extra_values);
80 result.SetBoolean("syncAllDataTypes", sync_all == SYNC_ALL_DATA);
81 result.SetBoolean("syncNothing", sync_all == SYNC_NOTHING);
82 result.SetBoolean("encryptAllData", encrypt_all == ENCRYPT_ALL_DATA);
83 result.SetBoolean("usePassphrase", !passphrase.empty());
84 if (!passphrase.empty())
85 result.SetString("passphrase", passphrase);
86 // Add all of our data types.
87 result.SetBoolean("appsSynced", types.Has(syncer::APPS));
88 result.SetBoolean("autofillSynced", types.Has(syncer::AUTOFILL));
89 result.SetBoolean("bookmarksSynced", types.Has(syncer::BOOKMARKS));
90 result.SetBoolean("extensionsSynced", types.Has(syncer::EXTENSIONS));
91 result.SetBoolean("passwordsSynced", types.Has(syncer::PASSWORDS));
92 result.SetBoolean("preferencesSynced", types.Has(syncer::PREFERENCES));
93 result.SetBoolean("tabsSynced", types.Has(syncer::PROXY_TABS));
94 result.SetBoolean("themesSynced", types.Has(syncer::THEMES));
95 result.SetBoolean("typedUrlsSynced", types.Has(syncer::TYPED_URLS));
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(actual_value, expected_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));
148 // Test instance of WebUI that tracks the data passed to
149 // CallJavascriptFunction().
150 class TestWebUI : public content::WebUI {
152 virtual ~TestWebUI() {
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 virtual void CallJavascriptFunction(const std::string& function_name)
170 call_data_.push_back(CallData());
171 call_data_.back().function_name = function_name;
174 virtual void CallJavascriptFunction(const std::string& function_name,
175 const base::Value& arg1) OVERRIDE {
176 call_data_.push_back(CallData());
177 call_data_.back().function_name = function_name;
178 call_data_.back().arg1 = arg1.DeepCopy();
181 virtual void CallJavascriptFunction(const std::string& function_name,
182 const base::Value& arg1,
183 const base::Value& arg2) OVERRIDE {
184 call_data_.push_back(CallData());
185 call_data_.back().function_name = function_name;
186 call_data_.back().arg1 = arg1.DeepCopy();
187 call_data_.back().arg2 = arg2.DeepCopy();
190 virtual content::WebContents* GetWebContents() const OVERRIDE {
193 virtual content::WebUIController* GetController() const OVERRIDE {
196 virtual void SetController(content::WebUIController* controller) OVERRIDE {}
197 virtual ui::ScaleFactor GetDeviceScaleFactor() const OVERRIDE {
198 return ui::SCALE_FACTOR_100P;
200 virtual const base::string16& GetOverriddenTitle() const OVERRIDE {
203 virtual void OverrideTitle(const base::string16& title) OVERRIDE {}
204 virtual content::PageTransition GetLinkTransitionType() const OVERRIDE {
205 return content::PAGE_TRANSITION_LINK;
207 virtual void SetLinkTransitionType(content::PageTransition type) OVERRIDE {}
208 virtual int GetBindings() const OVERRIDE {
211 virtual void SetBindings(int bindings) OVERRIDE {}
212 virtual void OverrideJavaScriptFrame(
213 const std::string& frame_name) OVERRIDE {}
214 virtual void AddMessageHandler(
215 content::WebUIMessageHandler* handler) OVERRIDE {}
216 virtual void RegisterMessageCallback(
217 const std::string& message,
218 const MessageCallback& callback) OVERRIDE {}
219 virtual void ProcessWebUIMessage(const GURL& source_url,
220 const std::string& message,
221 const base::ListValue& args) OVERRIDE {}
222 virtual void CallJavascriptFunction(const std::string& function_name,
223 const base::Value& arg1,
224 const base::Value& arg2,
225 const base::Value& arg3) OVERRIDE {}
226 virtual void CallJavascriptFunction(const std::string& function_name,
227 const base::Value& arg1,
228 const base::Value& arg2,
229 const base::Value& arg3,
230 const base::Value& arg4) OVERRIDE {}
231 virtual void CallJavascriptFunction(
232 const std::string& function_name,
233 const std::vector<const base::Value*>& args) OVERRIDE {}
237 CallData() : arg1(NULL), arg2(NULL) {}
238 std::string function_name;
242 const std::vector<CallData>& call_data() { return call_data_; }
244 std::vector<CallData> call_data_;
245 base::string16 temp_string_;
248 class TestingSyncSetupHandler : public SyncSetupHandler {
250 TestingSyncSetupHandler(content::WebUI* web_ui, Profile* profile)
251 : SyncSetupHandler(NULL),
255 virtual ~TestingSyncSetupHandler() {
259 virtual void FocusUI() OVERRIDE {}
261 virtual Profile* GetProfile() const OVERRIDE { return profile_; }
263 using SyncSetupHandler::is_configuring_sync;
266 #if !defined(OS_CHROMEOS)
267 virtual void DisplayGaiaLoginInNewTabOrWindow() OVERRIDE {}
270 // Weak pointer to parent profile.
272 DISALLOW_COPY_AND_ASSIGN(TestingSyncSetupHandler);
275 // The boolean parameter indicates whether the test is run with ClientOAuth
276 // or not. The test parameter is a bool: whether or not to test with/
277 // /ClientLogin enabled or not.
278 class SyncSetupHandlerTest : public testing::Test {
280 SyncSetupHandlerTest() : error_(GoogleServiceAuthError::NONE) {}
281 virtual void SetUp() OVERRIDE {
282 error_ = GoogleServiceAuthError::AuthErrorNone();
284 TestingProfile::Builder builder;
285 builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
286 FakeSigninManagerBase::Build);
287 profile_ = builder.Build();
290 mock_signin_ = static_cast<SigninManagerBase*>(
291 SigninManagerFactory::GetForProfile(profile_.get()));
292 mock_signin_->SetAuthenticatedUsername(GetTestUser());
293 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
296 mock_pss_ = static_cast<ProfileSyncServiceMock*>(
297 ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
299 ProfileSyncServiceMock::BuildMockProfileSyncService));
300 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
301 ON_CALL(*mock_pss_, GetPassphraseType()).WillByDefault(
302 Return(syncer::IMPLICIT_PASSPHRASE));
303 ON_CALL(*mock_pss_, GetPassphraseTime()).WillByDefault(
304 Return(base::Time()));
305 ON_CALL(*mock_pss_, GetExplicitPassphraseTime()).WillByDefault(
306 Return(base::Time()));
307 ON_CALL(*mock_pss_, GetRegisteredDataTypes())
308 .WillByDefault(Return(syncer::ModelTypeSet()));
310 mock_pss_->Initialize();
312 handler_.reset(new TestingSyncSetupHandler(&web_ui_, profile_.get()));
315 // Setup the expectations for calls made when displaying the config page.
316 void SetDefaultExpectationsForConfigPage() {
317 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn()).
318 WillRepeatedly(Return(true));
319 EXPECT_CALL(*mock_pss_, GetRegisteredDataTypes()).
320 WillRepeatedly(Return(GetAllTypes()));
321 EXPECT_CALL(*mock_pss_, GetPreferredDataTypes()).
322 WillRepeatedly(Return(GetAllTypes()));
323 EXPECT_CALL(*mock_pss_, GetActiveDataTypes()).
324 WillRepeatedly(Return(GetAllTypes()));
325 EXPECT_CALL(*mock_pss_, EncryptEverythingEnabled()).
326 WillRepeatedly(Return(false));
329 void SetupInitializedProfileSyncService() {
330 // An initialized ProfileSyncService will have already completed sync setup
331 // and will have an initialized sync backend.
332 ASSERT_TRUE(mock_signin_->IsInitialized());
333 EXPECT_CALL(*mock_pss_, sync_initialized()).WillRepeatedly(Return(true));
336 void ExpectConfig() {
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, "configure");
346 ASSERT_EQ(1U, web_ui_.call_data().size());
347 const TestWebUI::CallData& data = web_ui_.call_data()[0];
348 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
350 ASSERT_TRUE(data.arg1->GetAsString(&page));
351 EXPECT_EQ(page, "done");
354 void ExpectSpinnerAndClose() {
355 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
356 EXPECT_EQ(1U, web_ui_.call_data().size());
357 const TestWebUI::CallData& data = web_ui_.call_data()[0];
358 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
361 ASSERT_TRUE(data.arg1->GetAsString(&page));
362 EXPECT_EQ(page, "spinner");
363 // Cancelling the spinner dialog will cause CloseSyncSetup().
364 handler_->CloseSyncSetup();
366 LoginUIServiceFactory::GetForProfile(
367 profile_.get())->current_login_ui());
370 // It's difficult to notify sync listeners when using a ProfileSyncServiceMock
371 // so this helper routine dispatches an OnStateChanged() notification to the
372 // SyncStartupTracker.
373 void NotifySyncListeners() {
374 if (handler_->sync_startup_tracker_)
375 handler_->sync_startup_tracker_->OnStateChanged();
378 virtual std::string GetTestUser() {
379 return std::string(kTestUser);
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 class SyncSetupHandlerFirstSigninTest : public SyncSetupHandlerTest {
392 virtual std::string GetTestUser() OVERRIDE { return std::string(); }
395 TEST_F(SyncSetupHandlerTest, Basic) {
398 #if !defined(OS_CHROMEOS)
399 TEST_F(SyncSetupHandlerFirstSigninTest, DisplayBasicLogin) {
400 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
401 .WillRepeatedly(Return(false));
402 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
403 .WillRepeatedly(Return(false));
404 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
405 .WillRepeatedly(Return(false));
406 // Ensure that the user is not signed in before calling |HandleStartSignin()|.
407 SigninManager* manager = static_cast<SigninManager*>(mock_signin_);
409 handler_->HandleStartSignin(NULL);
411 // Sync setup hands off control to the gaia login tab.
413 LoginUIServiceFactory::GetForProfile(
414 profile_.get())->current_login_ui());
416 ASSERT_FALSE(handler_->is_configuring_sync());
418 handler_->CloseSyncSetup();
420 LoginUIServiceFactory::GetForProfile(
421 profile_.get())->current_login_ui());
424 TEST_F(SyncSetupHandlerTest, ShowSyncSetupWhenNotSignedIn) {
425 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
426 .WillRepeatedly(Return(false));
427 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
428 .WillRepeatedly(Return(false));
429 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
430 .WillRepeatedly(Return(false));
431 handler_->HandleShowSetupUI(NULL);
433 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
434 ASSERT_EQ(1U, web_ui_.call_data().size());
435 const TestWebUI::CallData& data = web_ui_.call_data()[0];
436 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
438 ASSERT_FALSE(handler_->is_configuring_sync());
440 LoginUIServiceFactory::GetForProfile(
441 profile_.get())->current_login_ui());
443 #endif // !defined(OS_CHROMEOS)
445 // Verifies that the handler correctly handles a cancellation when
446 // it is displaying the spinner to the user.
447 TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndCancel) {
448 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
449 .WillRepeatedly(Return(true));
450 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
451 .WillRepeatedly(Return(true));
452 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
453 .WillRepeatedly(Return(false));
454 error_ = GoogleServiceAuthError::AuthErrorNone();
455 EXPECT_CALL(*mock_pss_, sync_initialized()).WillRepeatedly(Return(false));
457 // We're simulating a user setting up sync, which would cause the backend to
458 // kick off initialization, but not download user data types. The sync
459 // backend will try to download control data types (e.g encryption info), but
460 // that won't finish for this test as we're simulating cancelling while the
461 // spinner is showing.
462 handler_->HandleShowSetupUI(NULL);
464 EXPECT_EQ(handler_.get(),
465 LoginUIServiceFactory::GetForProfile(
466 profile_.get())->current_login_ui());
468 ExpectSpinnerAndClose();
471 // Verifies that the handler correctly transitions from showing the spinner
472 // to showing a configuration page when sync setup completes successfully.
473 TEST_F(SyncSetupHandlerTest,
474 DisplayConfigureWithBackendDisabledAndSyncStartupCompleted) {
475 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
476 .WillRepeatedly(Return(true));
477 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
478 .WillRepeatedly(Return(true));
479 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
480 .WillRepeatedly(Return(false));
481 error_ = GoogleServiceAuthError::AuthErrorNone();
482 // Sync backend is stopped initially, and will start up.
483 EXPECT_CALL(*mock_pss_, sync_initialized())
484 .WillRepeatedly(Return(false));
485 SetDefaultExpectationsForConfigPage();
487 handler_->OpenSyncSetup();
489 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
490 EXPECT_EQ(1U, web_ui_.call_data().size());
492 const TestWebUI::CallData& data0 = web_ui_.call_data()[0];
493 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data0.function_name);
495 ASSERT_TRUE(data0.arg1->GetAsString(&page));
496 EXPECT_EQ(page, "spinner");
498 Mock::VerifyAndClearExpectations(mock_pss_);
499 // Now, act as if the ProfileSyncService has started up.
500 SetDefaultExpectationsForConfigPage();
501 EXPECT_CALL(*mock_pss_, sync_initialized())
502 .WillRepeatedly(Return(true));
503 error_ = GoogleServiceAuthError::AuthErrorNone();
504 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
505 NotifySyncListeners();
507 // We expect a second call to SyncSetupOverlay.showSyncSetupPage.
508 EXPECT_EQ(2U, web_ui_.call_data().size());
509 const TestWebUI::CallData& data1 = web_ui_.call_data().back();
510 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data1.function_name);
511 ASSERT_TRUE(data1.arg1->GetAsString(&page));
512 EXPECT_EQ(page, "configure");
513 base::DictionaryValue* dictionary;
514 ASSERT_TRUE(data1.arg2->GetAsDictionary(&dictionary));
515 CheckBool(dictionary, "passphraseFailed", false);
516 CheckBool(dictionary, "showSyncEverythingPage", false);
517 CheckBool(dictionary, "syncAllDataTypes", true);
518 CheckBool(dictionary, "encryptAllData", false);
519 CheckBool(dictionary, "usePassphrase", false);
522 // Verifies the case where the user cancels after the sync backend has
523 // initialized (meaning it already transitioned from the spinner to a proper
524 // configuration page, tested by
525 // DisplayConfigureWithBackendDisabledAndSigninSuccess), but before the user
526 // before the user has continued on.
527 TEST_F(SyncSetupHandlerTest,
528 DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess) {
529 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
530 .WillRepeatedly(Return(true));
531 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
532 .WillRepeatedly(Return(true));
533 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
534 .WillRepeatedly(Return(false));
535 error_ = GoogleServiceAuthError::AuthErrorNone();
536 EXPECT_CALL(*mock_pss_, sync_initialized())
537 .WillOnce(Return(false))
538 .WillRepeatedly(Return(true));
539 SetDefaultExpectationsForConfigPage();
540 handler_->OpenSyncSetup();
542 // It's important to tell sync the user cancelled the setup flow before we
543 // tell it we're through with the setup progress.
544 testing::InSequence seq;
545 EXPECT_CALL(*mock_pss_, DisableForUser());
546 EXPECT_CALL(*mock_pss_, SetSetupInProgress(false));
548 handler_->CloseSyncSetup();
550 LoginUIServiceFactory::GetForProfile(
551 profile_.get())->current_login_ui());
554 TEST_F(SyncSetupHandlerTest,
555 DisplayConfigureWithBackendDisabledAndSigninFailed) {
556 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
557 .WillRepeatedly(Return(true));
558 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
559 .WillRepeatedly(Return(true));
560 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
561 .WillRepeatedly(Return(false));
562 error_ = GoogleServiceAuthError::AuthErrorNone();
563 EXPECT_CALL(*mock_pss_, sync_initialized()).WillRepeatedly(Return(false));
565 handler_->OpenSyncSetup();
566 const TestWebUI::CallData& data = web_ui_.call_data()[0];
567 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
569 ASSERT_TRUE(data.arg1->GetAsString(&page));
570 EXPECT_EQ(page, "spinner");
571 Mock::VerifyAndClearExpectations(mock_pss_);
572 error_ = GoogleServiceAuthError(
573 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
574 EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
575 NotifySyncListeners();
577 // On failure, the dialog will be closed.
579 LoginUIServiceFactory::GetForProfile(
580 profile_.get())->current_login_ui());
583 #if !defined(OS_CHROMEOS)
585 class SyncSetupHandlerNonCrosTest : public SyncSetupHandlerTest {
587 SyncSetupHandlerNonCrosTest() {}
590 TEST_F(SyncSetupHandlerNonCrosTest, HandleGaiaAuthFailure) {
591 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
592 .WillRepeatedly(Return(false));
593 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
594 .WillRepeatedly(Return(false));
595 EXPECT_CALL(*mock_pss_, HasUnrecoverableError())
596 .WillRepeatedly(Return(false));
597 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
598 .WillRepeatedly(Return(false));
600 handler_->OpenSyncSetup();
602 ASSERT_FALSE(handler_->is_configuring_sync());
605 // TODO(kochi): We need equivalent tests for ChromeOS.
606 TEST_F(SyncSetupHandlerNonCrosTest, UnrecoverableErrorInitializingSync) {
607 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
608 .WillRepeatedly(Return(false));
609 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
610 .WillRepeatedly(Return(false));
611 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
612 .WillRepeatedly(Return(false));
614 handler_->OpenSyncSetup();
616 ASSERT_FALSE(handler_->is_configuring_sync());
619 TEST_F(SyncSetupHandlerNonCrosTest, GaiaErrorInitializingSync) {
620 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
621 .WillRepeatedly(Return(false));
622 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
623 .WillRepeatedly(Return(false));
624 EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted())
625 .WillRepeatedly(Return(false));
627 handler_->OpenSyncSetup();
629 ASSERT_FALSE(handler_->is_configuring_sync());
632 #endif // #if !defined(OS_CHROMEOS)
634 TEST_F(SyncSetupHandlerTest, TestSyncEverything) {
635 std::string args = GetConfiguration(
636 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS);
637 base::ListValue list_args;
638 list_args.Append(new base::StringValue(args));
639 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
640 .WillRepeatedly(Return(false));
641 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
642 .WillRepeatedly(Return(false));
643 SetupInitializedProfileSyncService();
644 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
645 handler_->HandleConfigure(&list_args);
647 // Ensure that we navigated to the "done" state since we don't need a
652 TEST_F(SyncSetupHandlerTest, TestSyncNothing) {
653 std::string args = GetConfiguration(
654 NULL, SYNC_NOTHING, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS);
655 base::ListValue list_args;
656 list_args.Append(new base::StringValue(args));
657 EXPECT_CALL(*mock_pss_, DisableForUser());
658 SetupInitializedProfileSyncService();
659 handler_->HandleConfigure(&list_args);
661 // We expect a call to SyncSetupOverlay.showSyncSetupPage.
662 ASSERT_EQ(1U, web_ui_.call_data().size());
663 const TestWebUI::CallData& data = web_ui_.call_data()[0];
664 EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name);
667 TEST_F(SyncSetupHandlerTest, TurnOnEncryptAll) {
668 std::string args = GetConfiguration(
669 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA);
670 base::ListValue list_args;
671 list_args.Append(new base::StringValue(args));
672 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
673 .WillRepeatedly(Return(false));
674 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
675 .WillRepeatedly(Return(false));
676 SetupInitializedProfileSyncService();
677 EXPECT_CALL(*mock_pss_, EnableEncryptEverything());
678 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
679 handler_->HandleConfigure(&list_args);
681 // Ensure that we navigated to the "done" state since we don't need a
686 TEST_F(SyncSetupHandlerTest, TestPassphraseStillRequired) {
687 std::string args = GetConfiguration(
688 NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS);
689 base::ListValue list_args;
690 list_args.Append(new base::StringValue(args));
691 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
692 .WillRepeatedly(Return(true));
693 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
694 .WillRepeatedly(Return(true));
695 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
696 .WillRepeatedly(Return(false));
697 SetupInitializedProfileSyncService();
698 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
699 SetDefaultExpectationsForConfigPage();
701 // We should navigate back to the configure page since we need a passphrase.
702 handler_->HandleConfigure(&list_args);
707 TEST_F(SyncSetupHandlerTest, SuccessfullySetPassphrase) {
708 base::DictionaryValue dict;
709 dict.SetBoolean("isGooglePassphrase", true);
710 std::string args = GetConfiguration(&dict,
715 base::ListValue list_args;
716 list_args.Append(new base::StringValue(args));
717 // Act as if an encryption passphrase is required the first time, then never
719 EXPECT_CALL(*mock_pss_, IsPassphraseRequired()).WillOnce(Return(true));
720 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
721 .WillRepeatedly(Return(false));
722 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
723 .WillRepeatedly(Return(false));
724 SetupInitializedProfileSyncService();
725 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
726 EXPECT_CALL(*mock_pss_, SetDecryptionPassphrase("gaiaPassphrase")).
727 WillOnce(Return(true));
729 handler_->HandleConfigure(&list_args);
730 // We should navigate to "done" page since we finished configuring.
734 TEST_F(SyncSetupHandlerTest, SelectCustomEncryption) {
735 base::DictionaryValue dict;
736 dict.SetBoolean("isGooglePassphrase", false);
737 std::string args = GetConfiguration(&dict,
742 base::ListValue list_args;
743 list_args.Append(new base::StringValue(args));
744 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
745 .WillRepeatedly(Return(false));
746 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
747 .WillRepeatedly(Return(false));
748 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
749 .WillRepeatedly(Return(false));
750 SetupInitializedProfileSyncService();
751 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
752 EXPECT_CALL(*mock_pss_,
753 SetEncryptionPassphrase("custom_passphrase",
754 ProfileSyncService::EXPLICIT));
756 handler_->HandleConfigure(&list_args);
757 // We should navigate to "done" page since we finished configuring.
761 TEST_F(SyncSetupHandlerTest, UnsuccessfullySetPassphrase) {
762 base::DictionaryValue dict;
763 dict.SetBoolean("isGooglePassphrase", true);
764 std::string args = GetConfiguration(&dict,
767 "invalid_passphrase",
769 base::ListValue list_args;
770 list_args.Append(new base::StringValue(args));
771 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
772 .WillRepeatedly(Return(true));
773 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
774 .WillRepeatedly(Return(true));
775 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
776 .WillRepeatedly(Return(false));
777 SetupInitializedProfileSyncService();
778 EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
779 EXPECT_CALL(*mock_pss_, SetDecryptionPassphrase("invalid_passphrase")).
780 WillOnce(Return(false));
782 SetDefaultExpectationsForConfigPage();
783 // We should navigate back to the configure page since we need a passphrase.
784 handler_->HandleConfigure(&list_args);
788 // Make sure we display an error message to the user due to the failed
790 const TestWebUI::CallData& data = web_ui_.call_data()[0];
791 base::DictionaryValue* dictionary;
792 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
793 CheckBool(dictionary, "passphraseFailed", true);
796 // Walks through each user selectable type, and tries to sync just that single
798 TEST_F(SyncSetupHandlerTest, TestSyncIndividualTypes) {
799 syncer::ModelTypeSet user_selectable_types = GetAllTypes();
800 syncer::ModelTypeSet::Iterator it;
801 for (it = user_selectable_types.First(); it.Good(); it.Inc()) {
802 syncer::ModelTypeSet type_to_set;
803 type_to_set.Put(it.Get());
804 std::string args = GetConfiguration(NULL,
809 base::ListValue list_args;
810 list_args.Append(new base::StringValue(args));
811 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
812 .WillRepeatedly(Return(false));
813 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
814 .WillRepeatedly(Return(false));
815 SetupInitializedProfileSyncService();
816 EXPECT_CALL(*mock_pss_,
817 OnUserChoseDatatypes(false, ModelTypeSetMatches(type_to_set)));
818 handler_->HandleConfigure(&list_args);
821 Mock::VerifyAndClearExpectations(mock_pss_);
822 web_ui_.ClearTrackedCalls();
826 TEST_F(SyncSetupHandlerTest, TestSyncAllManually) {
827 std::string args = GetConfiguration(NULL,
832 base::ListValue list_args;
833 list_args.Append(new base::StringValue(args));
834 EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
835 .WillRepeatedly(Return(false));
836 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
837 .WillRepeatedly(Return(false));
838 SetupInitializedProfileSyncService();
839 EXPECT_CALL(*mock_pss_,
840 OnUserChoseDatatypes(false, ModelTypeSetMatches(GetAllTypes())));
841 handler_->HandleConfigure(&list_args);
846 TEST_F(SyncSetupHandlerTest, ShowSyncSetup) {
847 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
848 .WillRepeatedly(Return(false));
849 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
850 .WillRepeatedly(Return(false));
851 SetupInitializedProfileSyncService();
852 // This should display the sync setup dialog (not login).
853 SetDefaultExpectationsForConfigPage();
854 handler_->OpenSyncSetup();
859 // We do not display signin on chromeos in the case of auth error.
860 TEST_F(SyncSetupHandlerTest, ShowSigninOnAuthError) {
861 // Initialize the system to a signed in state, but with an auth error.
862 error_ = GoogleServiceAuthError(
863 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
865 SetupInitializedProfileSyncService();
866 mock_signin_->SetAuthenticatedUsername(kTestUser);
867 FakeAuthStatusProvider provider(
868 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get())->
869 signin_error_controller());
870 provider.SetAuthError(kTestUser, error_);
871 EXPECT_CALL(*mock_pss_, IsSyncEnabledAndLoggedIn())
872 .WillRepeatedly(Return(true));
873 EXPECT_CALL(*mock_pss_, IsOAuthRefreshTokenAvailable())
874 .WillRepeatedly(Return(true));
875 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
876 .WillRepeatedly(Return(false));
877 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
878 .WillRepeatedly(Return(false));
879 EXPECT_CALL(*mock_pss_, sync_initialized()).WillRepeatedly(Return(false));
881 #if defined(OS_CHROMEOS)
882 // On ChromeOS, auth errors are ignored - instead we just try to start the
883 // sync backend (which will fail due to the auth error). This should only
884 // happen if the user manually navigates to chrome://settings/syncSetup -
885 // clicking on the button in the UI will sign the user out rather than
886 // displaying a spinner. Should be no visible UI on ChromeOS in this case.
887 EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile(
888 profile_.get())->current_login_ui());
891 // On ChromeOS, this should display the spinner while we try to startup the
892 // sync backend, and on desktop this displays the login dialog.
893 handler_->OpenSyncSetup();
895 // Sync setup is closed when re-auth is in progress.
897 LoginUIServiceFactory::GetForProfile(
898 profile_.get())->current_login_ui());
900 ASSERT_FALSE(handler_->is_configuring_sync());
904 TEST_F(SyncSetupHandlerTest, ShowSetupSyncEverything) {
905 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
906 .WillRepeatedly(Return(false));
907 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
908 .WillRepeatedly(Return(false));
909 SetupInitializedProfileSyncService();
910 SetDefaultExpectationsForConfigPage();
911 // This should display the sync setup dialog (not login).
912 handler_->OpenSyncSetup();
915 const TestWebUI::CallData& data = web_ui_.call_data()[0];
916 base::DictionaryValue* dictionary;
917 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
918 CheckBool(dictionary, "showSyncEverythingPage", false);
919 CheckBool(dictionary, "syncAllDataTypes", true);
920 CheckBool(dictionary, "appsRegistered", true);
921 CheckBool(dictionary, "autofillRegistered", true);
922 CheckBool(dictionary, "bookmarksRegistered", true);
923 CheckBool(dictionary, "extensionsRegistered", true);
924 CheckBool(dictionary, "passwordsRegistered", true);
925 CheckBool(dictionary, "preferencesRegistered", true);
926 CheckBool(dictionary, "tabsRegistered", true);
927 CheckBool(dictionary, "themesRegistered", true);
928 CheckBool(dictionary, "typedUrlsRegistered", true);
929 CheckBool(dictionary, "showPassphrase", false);
930 CheckBool(dictionary, "usePassphrase", false);
931 CheckBool(dictionary, "passphraseFailed", false);
932 CheckBool(dictionary, "encryptAllData", false);
933 CheckConfigDataTypeArguments(dictionary, SYNC_ALL_DATA, GetAllTypes());
936 TEST_F(SyncSetupHandlerTest, ShowSetupManuallySyncAll) {
937 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
938 .WillRepeatedly(Return(false));
939 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
940 .WillRepeatedly(Return(false));
941 SetupInitializedProfileSyncService();
942 sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
943 sync_prefs.SetKeepEverythingSynced(false);
944 SetDefaultExpectationsForConfigPage();
945 // This should display the sync setup dialog (not login).
946 handler_->OpenSyncSetup();
949 const TestWebUI::CallData& data = web_ui_.call_data()[0];
950 base::DictionaryValue* dictionary;
951 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
952 CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, GetAllTypes());
955 TEST_F(SyncSetupHandlerTest, ShowSetupSyncForAllTypesIndividually) {
956 syncer::ModelTypeSet user_selectable_types = GetAllTypes();
957 syncer::ModelTypeSet::Iterator it;
958 for (it = user_selectable_types.First(); it.Good(); it.Inc()) {
959 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
960 .WillRepeatedly(Return(false));
961 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
962 .WillRepeatedly(Return(false));
963 SetupInitializedProfileSyncService();
964 sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
965 sync_prefs.SetKeepEverythingSynced(false);
966 SetDefaultExpectationsForConfigPage();
967 syncer::ModelTypeSet types;
969 EXPECT_CALL(*mock_pss_, GetPreferredDataTypes()).
970 WillRepeatedly(Return(types));
972 // This should display the sync setup dialog (not login).
973 handler_->OpenSyncSetup();
976 // Close the config overlay.
977 LoginUIServiceFactory::GetForProfile(profile_.get())->LoginUIClosed(
979 const TestWebUI::CallData& data = web_ui_.call_data()[0];
980 base::DictionaryValue* dictionary;
981 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
982 CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, types);
983 Mock::VerifyAndClearExpectations(mock_pss_);
984 // Clean up so we can loop back to display the dialog again.
985 web_ui_.ClearTrackedCalls();
989 TEST_F(SyncSetupHandlerTest, ShowSetupGaiaPassphraseRequired) {
990 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
991 .WillRepeatedly(Return(true));
992 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
993 .WillRepeatedly(Return(false));
994 SetupInitializedProfileSyncService();
995 SetDefaultExpectationsForConfigPage();
997 // This should display the sync setup dialog (not login).
998 handler_->OpenSyncSetup();
1001 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1002 base::DictionaryValue* dictionary;
1003 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1004 CheckBool(dictionary, "showPassphrase", true);
1005 CheckBool(dictionary, "usePassphrase", false);
1006 CheckBool(dictionary, "passphraseFailed", false);
1009 TEST_F(SyncSetupHandlerTest, ShowSetupCustomPassphraseRequired) {
1010 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1011 .WillRepeatedly(Return(true));
1012 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1013 .WillRepeatedly(Return(true));
1014 EXPECT_CALL(*mock_pss_, GetPassphraseType())
1015 .WillRepeatedly(Return(syncer::CUSTOM_PASSPHRASE));
1016 SetupInitializedProfileSyncService();
1017 SetDefaultExpectationsForConfigPage();
1019 // This should display the sync setup dialog (not login).
1020 handler_->OpenSyncSetup();
1023 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1024 base::DictionaryValue* dictionary;
1025 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1026 CheckBool(dictionary, "showPassphrase", true);
1027 CheckBool(dictionary, "usePassphrase", true);
1028 CheckBool(dictionary, "passphraseFailed", false);
1031 TEST_F(SyncSetupHandlerTest, ShowSetupEncryptAll) {
1032 EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
1033 .WillRepeatedly(Return(false));
1034 EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
1035 .WillRepeatedly(Return(false));
1036 SetupInitializedProfileSyncService();
1037 SetDefaultExpectationsForConfigPage();
1038 EXPECT_CALL(*mock_pss_, EncryptEverythingEnabled()).
1039 WillRepeatedly(Return(true));
1041 // This should display the sync setup dialog (not login).
1042 handler_->OpenSyncSetup();
1045 const TestWebUI::CallData& data = web_ui_.call_data()[0];
1046 base::DictionaryValue* dictionary;
1047 ASSERT_TRUE(data.arg2->GetAsDictionary(&dictionary));
1048 CheckBool(dictionary, "encryptAllData", true);