| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/settings/people_handler.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/i18n/time_formatting.h" |
| #include "base/json/json_writer.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/defaults.h" |
| #include "chrome/browser/first_run/first_run.h" |
| #include "chrome/browser/signin/account_consistency_mode_manager.h" |
| #include "chrome/browser/signin/chrome_signin_client_factory.h" |
| #include "chrome/browser/signin/chrome_signin_client_test_util.h" |
| #include "chrome/browser/signin/dice_web_signin_interceptor.h" |
| #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" |
| #include "chrome/browser/signin/signin_error_controller_factory.h" |
| #include "chrome/browser/signin/signin_util.h" |
| #include "chrome/browser/sync/sync_service_factory.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/browser/ui/webui/signin/login_ui_service.h" |
| #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/test/base/browser_with_test_window_test.h" |
| #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
| #include "chrome/test/base/scoped_testing_local_state.h" |
| #include "chrome/test/base/test_chrome_web_ui_controller_factory.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/public/base/account_consistency_method.h" |
| #include "components/signin/public/base/consent_level.h" |
| #include "components/signin/public/base/signin_pref_names.h" |
| #include "components/signin/public/base/signin_prefs.h" |
| #include "components/signin/public/base/signin_switches.h" |
| #include "components/signin/public/identity_manager/accounts_mutator.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/signin/public/identity_manager/identity_test_environment.h" |
| #include "components/signin/public/identity_manager/identity_test_utils.h" |
| #include "components/signin/public/identity_manager/primary_account_mutator.h" |
| #include "components/sync/base/passphrase_enums.h" |
| #include "components/sync/base/user_selectable_type.h" |
| #include "components/sync/service/sync_user_settings_impl.h" |
| #include "components/sync/test/test_sync_service.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "content/public/browser/web_ui_controller.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "content/public/test/scoped_web_ui_controller_factory_registration.h" |
| #include "content/public/test/test_web_ui.h" |
| #include "content/public/test/web_contents_tester.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| using signin::ConsentLevel; |
| using ::testing::_; |
| using ::testing::ByMove; |
| using ::testing::Const; |
| using ::testing::Invoke; |
| using ::testing::IsEmpty; |
| using ::testing::Mock; |
| using ::testing::Return; |
| using ::testing::Values; |
| |
| constexpr char kTestUser[] = "chrome_p13n_test@gmail.com"; |
| constexpr char kTestCallbackId[] = "test-callback-id"; |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| // Event fired when calling |
| // `PeopleHandler::UpdateChromeSigninUserChoiceInfo()`. |
| constexpr char kChromeSigninUserChoiceInfoChangeEventName[] = |
| "chrome-signin-user-choice-info-change"; |
| |
| // Event fired when calling `PeopleHandler::UpdateSyncStatus()`. |
| constexpr char kSyncStatusChangeEventName[] = "sync-status-changed"; |
| #endif |
| |
| // Returns a UserSelectableTypeSet with all types set. |
| syncer::UserSelectableTypeSet GetAllTypes() { |
| return syncer::UserSelectableTypeSet::All(); |
| } |
| |
| enum SyncAllDataConfig { SYNC_ALL_DATA, CHOOSE_WHAT_TO_SYNC }; |
| |
| // Create a json-format string with the key/value pairs appropriate for a call |
| // to HandleSetDatatypes(). |
| std::string GetConfiguration(SyncAllDataConfig sync_all, |
| syncer::UserSelectableTypeSet types) { |
| base::Value::Dict result; |
| result.Set("syncAllDataTypes", sync_all == SYNC_ALL_DATA); |
| // Add all of our data types. |
| result.Set("appsSynced", types.Has(syncer::UserSelectableType::kApps)); |
| result.Set("autofillSynced", |
| types.Has(syncer::UserSelectableType::kAutofill)); |
| result.Set("bookmarksSynced", |
| types.Has(syncer::UserSelectableType::kBookmarks)); |
| result.Set("compareSynced", types.Has(syncer::UserSelectableType::kCompare)); |
| result.Set("cookiesSynced", types.Has(syncer::UserSelectableType::kCookies)); |
| result.Set("extensionsSynced", |
| types.Has(syncer::UserSelectableType::kExtensions)); |
| result.Set("passwordsSynced", |
| types.Has(syncer::UserSelectableType::kPasswords)); |
| result.Set("paymentsSynced", |
| types.Has(syncer::UserSelectableType::kPayments)); |
| result.Set("preferencesSynced", |
| types.Has(syncer::UserSelectableType::kPreferences)); |
| result.Set("readingListSynced", |
| types.Has(syncer::UserSelectableType::kReadingList)); |
| result.Set("savedTabGroupsSynced", |
| types.Has(syncer::UserSelectableType::kSavedTabGroups)); |
| result.Set("sharedTabGroupDataSynced", |
| types.Has(syncer::UserSelectableType::kSharedTabGroupData)); |
| result.Set("tabsSynced", types.Has(syncer::UserSelectableType::kTabs)); |
| result.Set("themesSynced", types.Has(syncer::UserSelectableType::kThemes)); |
| result.Set("typedUrlsSynced", |
| types.Has(syncer::UserSelectableType::kHistory)); |
| |
| std::string args; |
| base::JSONWriter::Write(result, &args); |
| return args; |
| } |
| |
| // Checks whether the passed |dictionary| contains a |key| with the given |
| // |expected_value|. This will fail if the key isn't present, even if |
| // |expected_value| is false. |
| void ExpectHasBoolKey(const base::Value::Dict& dictionary, |
| const std::string& key, |
| bool expected_value) { |
| ASSERT_TRUE(dictionary.contains(key)) << "No value found for " << key; |
| ASSERT_TRUE(dictionary.FindBool(key).has_value()) << key << " has wrong type"; |
| EXPECT_EQ(expected_value, *dictionary.FindBool(key)) |
| << "Mismatch found for " << key; |
| } |
| |
| // Checks to make sure that the values stored in |dictionary| match the values |
| // expected by the showSyncSetupPage() JS function for a given set of data |
| // types. |
| void CheckConfigDataTypeArguments(const base::Value::Dict& dictionary, |
| SyncAllDataConfig config, |
| syncer::UserSelectableTypeSet types) { |
| ExpectHasBoolKey(dictionary, "syncAllDataTypes", config == SYNC_ALL_DATA); |
| ExpectHasBoolKey(dictionary, "appsSynced", |
| types.Has(syncer::UserSelectableType::kApps)); |
| ExpectHasBoolKey(dictionary, "autofillSynced", |
| types.Has(syncer::UserSelectableType::kAutofill)); |
| ExpectHasBoolKey(dictionary, "bookmarksSynced", |
| types.Has(syncer::UserSelectableType::kBookmarks)); |
| ExpectHasBoolKey(dictionary, "extensionsSynced", |
| types.Has(syncer::UserSelectableType::kExtensions)); |
| ExpectHasBoolKey(dictionary, "passwordsSynced", |
| types.Has(syncer::UserSelectableType::kPasswords)); |
| ExpectHasBoolKey(dictionary, "preferencesSynced", |
| types.Has(syncer::UserSelectableType::kPreferences)); |
| ExpectHasBoolKey(dictionary, "readingListSynced", |
| types.Has(syncer::UserSelectableType::kReadingList)); |
| ExpectHasBoolKey(dictionary, "savedTabGroupsSynced", |
| types.Has(syncer::UserSelectableType::kSavedTabGroups)); |
| ExpectHasBoolKey(dictionary, "tabsSynced", |
| types.Has(syncer::UserSelectableType::kTabs)); |
| ExpectHasBoolKey(dictionary, "themesSynced", |
| types.Has(syncer::UserSelectableType::kThemes)); |
| ExpectHasBoolKey(dictionary, "typedUrlsSynced", |
| types.Has(syncer::UserSelectableType::kHistory)); |
| } |
| |
| std::unique_ptr<KeyedService> BuildTestSyncService( |
| content::BrowserContext* context) { |
| return std::make_unique<syncer::TestSyncService>(); |
| } |
| |
| } // namespace |
| |
| namespace settings { |
| |
| class TestingPeopleHandler : public PeopleHandler { |
| public: |
| TestingPeopleHandler(content::WebUI* web_ui, Profile* profile) |
| : PeopleHandler(profile) { |
| set_web_ui(web_ui); |
| } |
| |
| TestingPeopleHandler(const TestingPeopleHandler&) = delete; |
| TestingPeopleHandler& operator=(const TestingPeopleHandler&) = delete; |
| |
| using PeopleHandler::is_configuring_sync; |
| |
| private: |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| void DisplayGaiaLoginInNewTabOrWindow( |
| signin_metrics::AccessPoint access_point) override {} |
| #endif |
| }; |
| |
| class TestWebUIProvider |
| : public TestChromeWebUIControllerFactory::WebUIProvider { |
| public: |
| std::unique_ptr<content::WebUIController> NewWebUI(content::WebUI* web_ui, |
| const GURL& url) override { |
| return std::make_unique<content::WebUIController>(web_ui); |
| } |
| }; |
| |
| class PeopleHandlerTest : public ChromeRenderViewHostTestHarness { |
| public: |
| PeopleHandlerTest() = default; |
| |
| PeopleHandlerTest(const PeopleHandlerTest&) = delete; |
| PeopleHandlerTest& operator=(const PeopleHandlerTest&) = delete; |
| |
| ~PeopleHandlerTest() override = default; |
| |
| void SetUp() override { |
| ChromeRenderViewHostTestHarness::SetUp(); |
| |
| identity_test_env_adaptor_ = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile()); |
| |
| sync_service_ = static_cast<syncer::TestSyncService*>( |
| SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( |
| profile(), base::BindRepeating(&BuildTestSyncService))); |
| |
| sync_service_->SetSignedOut(); |
| } |
| |
| void TearDown() override { |
| sync_service_ = nullptr; |
| DestroyPeopleHandler(); |
| identity_test_env_adaptor_.reset(); |
| ChromeRenderViewHostTestHarness::TearDown(); |
| } |
| |
| TestingProfile::TestingFactories GetTestingFactories() const override { |
| return IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| } |
| |
| void SigninUserWithoutSyncFeature() { |
| const CoreAccountInfo account_info = identity_test_env()->SetPrimaryAccount( |
| kTestUser, signin::ConsentLevel::kSignin); |
| sync_service_->SetSignedInWithoutSyncFeature(account_info); |
| } |
| |
| void SigninUserAndTurnSyncFeatureOn() { |
| const CoreAccountInfo account_info = identity_test_env()->SetPrimaryAccount( |
| kTestUser, signin::ConsentLevel::kSync); |
| sync_service_->SetSignedInWithSyncFeatureOn(account_info); |
| } |
| |
| void CreatePeopleHandler() { |
| handler_ = std::make_unique<TestingPeopleHandler>(&web_ui_, profile()); |
| handler_->AllowJavascript(); |
| web_ui_.set_web_contents(web_contents()); |
| } |
| |
| void DestroyPeopleHandler() { |
| if (handler_) { |
| handler_->set_web_ui(nullptr); |
| handler_->DisallowJavascript(); |
| handler_ = nullptr; |
| } |
| } |
| |
| void ExpectPageStatusResponse(const std::string& expected_status) { |
| auto& data = *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", data.function_name()); |
| |
| ASSERT_TRUE(data.arg1()->is_string()); |
| EXPECT_EQ(kTestCallbackId, data.arg1()->GetString()); |
| ASSERT_TRUE(data.arg2()->is_bool()); |
| EXPECT_TRUE(data.arg2()->GetBool()); |
| ASSERT_TRUE(data.arg3()->is_string()); |
| EXPECT_EQ(expected_status, data.arg3()->GetString()); |
| } |
| |
| // Expects a call to ResolveJavascriptCallback() with |should_succeed| as its |
| // argument. |
| void ExpectSetPassphraseSuccess(bool should_succeed) { |
| EXPECT_EQ(1u, web_ui_.call_data().size()); |
| const auto& data = *web_ui_.call_data()[0]; |
| EXPECT_EQ("cr.webUIResponse", data.function_name()); |
| EXPECT_TRUE(data.arg2()->is_bool()); |
| EXPECT_TRUE(data.arg2()->GetBool()) |
| << "Callback should be resolved with a boolean indicating the success, " |
| "never rejected."; |
| |
| EXPECT_TRUE(data.arg3()->is_bool()); |
| EXPECT_EQ(should_succeed, data.arg3()->GetBool()); |
| } |
| |
| std::vector<const base::Value*> GetAllFiredValuesForEventName( |
| const std::string& event_name) { |
| std::vector<const base::Value*> arguments; |
| for (const std::unique_ptr<content::TestWebUI::CallData>& data : |
| web_ui_.call_data()) { |
| if (data->function_name() == "cr.webUIListenerCallback" && |
| data->arg1()->is_string() && |
| data->arg1()->GetString() == event_name) { |
| arguments.push_back(data->arg2()); |
| } |
| } |
| return arguments; |
| } |
| |
| // Returns all fired sync-prefs-changed events, without any validation. |
| std::vector<const base::Value*> GetFiredSyncPrefsChanged() { |
| return GetAllFiredValuesForEventName("sync-prefs-changed"); |
| } |
| |
| // Must be called at most once per test to check if a sync-prefs-changed |
| // event happened. Returns the single fired value. |
| base::Value::Dict ExpectSyncPrefsChanged() { |
| std::vector<const base::Value*> args = GetFiredSyncPrefsChanged(); |
| EXPECT_EQ(1U, args.size()); |
| EXPECT_NE(args[0], nullptr); |
| EXPECT_TRUE(args[0]->is_dict()); |
| return args[0]->GetDict().Clone(); |
| } |
| |
| // Must be called at most once per test to check if a sync-status-changed |
| // event happened. Returns the single fired value. |
| base::Value::Dict ExpectSyncStatusChanged() { |
| std::vector<const base::Value*> args = |
| GetAllFiredValuesForEventName("sync-status-changed"); |
| EXPECT_EQ(1U, args.size()); |
| EXPECT_NE(args[0], nullptr); |
| EXPECT_TRUE(args[0]->is_dict()); |
| return args[0]->GetDict().Clone(); |
| } |
| |
| signin::IdentityTestEnvironment* identity_test_env() { |
| return identity_test_env_adaptor_->identity_test_env(); |
| } |
| |
| signin::IdentityManager* identity_manager() { |
| return identity_test_env()->identity_manager(); |
| } |
| |
| syncer::TestSyncUserSettings* sync_user_settings() { |
| return sync_service_->GetUserSettings(); |
| } |
| |
| std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> |
| identity_test_env_adaptor_; |
| raw_ptr<syncer::TestSyncService> sync_service_; |
| content::TestWebUI web_ui_; |
| TestWebUIProvider test_provider_; |
| std::unique_ptr<TestChromeWebUIControllerFactory> test_factory_; |
| std::unique_ptr<TestingPeopleHandler> handler_; |
| }; |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F(PeopleHandlerTest, DisplayBasicLogin) { |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| ConsentLevel::kSignin)); |
| CreatePeopleHandler(); |
| // Test that the HandleStartSignin call enables JavaScript. |
| handler_->DisallowJavascript(); |
| |
| handler_->HandleStartSignin(base::Value::List()); |
| |
| // Sync setup hands off control to the gaia login tab. |
| EXPECT_EQ( |
| nullptr, |
| LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); |
| |
| ASSERT_FALSE(handler_->is_configuring_sync()); |
| |
| handler_->CloseSyncSetup(); |
| EXPECT_EQ( |
| nullptr, |
| LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); |
| } |
| |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) { |
| SigninUserAndTurnSyncFeatureOn(); |
| sync_user_settings()->ClearInitialSyncFeatureSetupComplete(); |
| |
| CreatePeopleHandler(); |
| |
| ASSERT_THAT(sync_service_->GetDisableReasons(), IsEmpty()); |
| |
| sync_service_->SetTransportState( |
| syncer::SyncService::TransportState::INITIALIZING); |
| |
| // We're simulating a user setting up sync, which would cause the engine to |
| // kick off initialization, but not download user data types. The sync |
| // engine will try to download control data types (e.g encryption info), but |
| // that won't finish for this test as we're simulating cancelling while the |
| // spinner is showing. |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| EXPECT_EQ( |
| handler_.get(), |
| LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); |
| |
| EXPECT_EQ(0U, web_ui_.call_data().size()); |
| |
| handler_->CloseSyncSetup(); |
| EXPECT_EQ( |
| nullptr, |
| LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); |
| } |
| |
| // Verifies that the handler only sends the sync pref updates once the engine is |
| // initialized. |
| TEST_F(PeopleHandlerTest, |
| DisplayConfigureWithEngineDisabledAndSyncStartupCompleted) { |
| SigninUserAndTurnSyncFeatureOn(); |
| sync_user_settings()->ClearInitialSyncFeatureSetupComplete(); |
| |
| CreatePeopleHandler(); |
| |
| ASSERT_THAT(sync_service_->GetDisableReasons(), IsEmpty()); |
| |
| // Sync engine is stopped initially, and will start up. |
| sync_service_->SetTransportState( |
| syncer::SyncService::TransportState::START_DEFERRED); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| // `SetSyncFeatureRequested()` should have triggered initialization. |
| EXPECT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::INITIALIZING); |
| |
| // No pref updates sent yet, because the engine is not initialized. |
| EXPECT_EQ(0U, GetFiredSyncPrefsChanged().size()); |
| web_ui_.ClearTrackedCalls(); |
| |
| // Now, act as if the SyncService has started up. |
| sync_service_->SetTransportState(syncer::SyncService::TransportState::ACTIVE); |
| sync_service_->FireStateChanged(); |
| |
| // Updates for the sync status, sync prefs and trusted vault opt-in are sent. |
| EXPECT_EQ(3U, web_ui_.call_data().size()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "syncAllDataTypes", true); |
| ExpectHasBoolKey(dictionary, "customPassphraseAllowed", true); |
| ExpectHasBoolKey(dictionary, "encryptAllData", false); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", false); |
| ExpectHasBoolKey(dictionary, "trustedVaultKeysRequired", false); |
| } |
| |
| // Verifies the case where the user cancels after the sync engine has |
| // initialized. This isn't reachable on Ash because |
| // IsInitialSyncFeatureSetupComplete() always returns true. |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F(PeopleHandlerTest, |
| DisplayConfigureWithEngineDisabledAndCancelAfterSigninSuccess) { |
| SigninUserAndTurnSyncFeatureOn(); |
| sync_user_settings()->ClearInitialSyncFeatureSetupComplete(); |
| |
| CreatePeopleHandler(); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| EXPECT_TRUE(sync_service_->IsSetupInProgress()); |
| |
| // Sync engine becomes active, so |handler_| is notified. |
| ASSERT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::ACTIVE); |
| |
| handler_->CloseSyncSetup(); |
| EXPECT_EQ( |
| nullptr, |
| LoginUIServiceFactory::GetForProfile(profile())->current_login_ui()); |
| |
| EXPECT_FALSE(sync_service_->IsSetupInProgress()); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| TEST_F(PeopleHandlerTest, RestartSyncAfterDashboardClear) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_service_->MimicDashboardClear(); |
| |
| ASSERT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::INITIALIZING); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_TRUE(sync_user_settings()->IsSyncFeatureDisabledViaDashboard()); |
| #else // BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_FALSE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| EXPECT_FALSE(sync_user_settings()->IsSyncFeatureDisabledViaDashboard()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // Since the engine is not initialized yet, no prefs should be sent. |
| EXPECT_EQ(0U, GetFiredSyncPrefsChanged().size()); |
| |
| // Now, act as if the SyncService has started up. |
| sync_service_->SetTransportState(syncer::SyncService::TransportState::ACTIVE); |
| sync_service_->FireStateChanged(); |
| |
| // Upon initialization of the engine, the new prefs should be sent. |
| ExpectSyncPrefsChanged(); |
| } |
| |
| // Tests that signals not related to user intention to configure sync don't |
| // trigger sync engine start. |
| TEST_F(PeopleHandlerTest, OnlyStartEngineWhenConfiguringSync) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_service_->SetTransportState( |
| syncer::SyncService::TransportState::START_DEFERRED); |
| sync_service_->FireStateChanged(); |
| EXPECT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::START_DEFERRED); |
| } |
| |
| TEST_F(PeopleHandlerTest, AcquireSyncBlockerWhenLoadingSyncSettingsSubpage) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| // We set up a factory override here to prevent a new web ui from being |
| // created when we navigate to a page that would normally create one. |
| TestChromeWebUIControllerFactory test_factory; |
| content::ScopedWebUIControllerFactoryRegistration factory_registration( |
| &test_factory, ChromeWebUIControllerFactory::GetInstance()); |
| test_factory.AddFactoryOverride( |
| chrome::GetSettingsUrl(chrome::kSyncSetupSubPage).host(), |
| &test_provider_); |
| |
| EXPECT_FALSE(handler_->sync_blocker_); |
| |
| auto navigation = content::NavigationSimulator::CreateBrowserInitiated( |
| chrome::GetSettingsUrl(chrome::kSyncSetupSubPage), web_contents()); |
| navigation->Start(); |
| handler_->InitializeSyncBlocker(); |
| |
| EXPECT_TRUE(handler_->sync_blocker_); |
| } |
| |
| TEST_F(PeopleHandlerTest, UnrecoverableErrorInitializingSync) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_service_->SetDisableReasons(syncer::SyncService::DisableReasonSet( |
| {syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR})); |
| sync_user_settings()->ClearInitialSyncFeatureSetupComplete(); |
| sync_service_->SetTransportState( |
| syncer::SyncService::TransportState::DISABLED); |
| |
| // Open the web UI. |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| ASSERT_FALSE(handler_->is_configuring_sync()); |
| } |
| |
| TEST_F(PeopleHandlerTest, GaiaErrorInitializingSync) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_service_->SetDisableReasons(syncer::SyncService::DisableReasonSet( |
| {syncer::SyncService::DISABLE_REASON_NOT_SIGNED_IN})); |
| sync_user_settings()->ClearInitialSyncFeatureSetupComplete(); |
| sync_service_->SetTransportState( |
| syncer::SyncService::TransportState::DISABLED); |
| |
| // Open the web UI. |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| ASSERT_FALSE(handler_->is_configuring_sync()); |
| } |
| |
| TEST_F(PeopleHandlerTest, TestSyncEverything) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetSelectedTypes(/*sync_everything=*/false, |
| /*types=*/GetAllTypes()); |
| |
| std::string args = GetConfiguration(SYNC_ALL_DATA, GetAllTypes()); |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(args); |
| handler_->HandleSetDatatypes(list_args); |
| EXPECT_TRUE(sync_user_settings()->IsSyncEverythingEnabled()); |
| |
| ExpectPageStatusResponse(PeopleHandler::kConfigurePageStatus); |
| } |
| |
| TEST_F(PeopleHandlerTest, EnterCorrectExistingPassphrase) { |
| const std::string kCorrectPassphrase = "correct_passphrase"; |
| |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetPassphraseRequired(kCorrectPassphrase); |
| |
| ASSERT_TRUE(sync_user_settings()->IsPassphraseRequired()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(kCorrectPassphrase); |
| handler_->HandleSetDecryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(true); |
| |
| EXPECT_FALSE(sync_user_settings()->IsPassphraseRequired()); |
| } |
| |
| TEST_F(PeopleHandlerTest, SuccessfullyCreateCustomPassphrase) { |
| const std::string kPassphrase = "custom_passphrase"; |
| |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(kPassphrase); |
| handler_->HandleSetEncryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(true); |
| |
| EXPECT_EQ(sync_user_settings()->GetEncryptionPassphrase(), kPassphrase); |
| } |
| |
| TEST_F(PeopleHandlerTest, EnterWrongExistingPassphrase) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetPassphraseRequired("correct_passphrase"); |
| |
| ASSERT_TRUE(sync_user_settings()->IsPassphraseRequired()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append("invalid_passphrase"); |
| handler_->HandleSetDecryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(false); |
| |
| ASSERT_TRUE(sync_user_settings()->IsPassphraseRequired()); |
| } |
| |
| TEST_F(PeopleHandlerTest, CannotCreateBlankPassphrase) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(""); |
| handler_->HandleSetEncryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(false); |
| |
| ASSERT_FALSE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| } |
| |
| // Walks through each user selectable type, and tries to sync just that single |
| // data type. |
| TEST_F(PeopleHandlerTest, TestSyncIndividualTypes) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| for (syncer::UserSelectableType type : GetAllTypes()) { |
| syncer::UserSelectableTypeSet type_to_set; |
| type_to_set.Put(type); |
| |
| std::string args = GetConfiguration(CHOOSE_WHAT_TO_SYNC, type_to_set); |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(args); |
| |
| handler_->HandleSetDatatypes(list_args); |
| ExpectPageStatusResponse(PeopleHandler::kConfigurePageStatus); |
| |
| EXPECT_FALSE(sync_user_settings()->IsSyncEverythingEnabled()); |
| EXPECT_EQ(sync_user_settings()->GetSelectedTypes(), type_to_set); |
| } |
| } |
| |
| TEST_F(PeopleHandlerTest, TestSyncAllManually) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| std::string args = GetConfiguration(CHOOSE_WHAT_TO_SYNC, GetAllTypes()); |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(args); |
| handler_->HandleSetDatatypes(list_args); |
| |
| ExpectPageStatusResponse(PeopleHandler::kConfigurePageStatus); |
| |
| EXPECT_FALSE(sync_user_settings()->IsSyncEverythingEnabled()); |
| EXPECT_EQ(sync_user_settings()->GetSelectedTypes(), GetAllTypes()); |
| } |
| |
| TEST_F(PeopleHandlerTest, NonRegisteredType) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| // Simulate apps not being registered. |
| syncer::UserSelectableTypeSet registered_types = GetAllTypes(); |
| registered_types.Remove(syncer::UserSelectableType::kApps); |
| sync_user_settings()->SetRegisteredSelectableTypes(registered_types); |
| |
| // Simulate "Sync everything" being turned off, but all individual |
| // toggles left on. |
| std::string config = GetConfiguration(CHOOSE_WHAT_TO_SYNC, GetAllTypes()); |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append(config); |
| |
| // Only the registered types are selected. |
| handler_->HandleSetDatatypes(list_args); |
| EXPECT_FALSE(sync_user_settings()->IsSyncEverythingEnabled()); |
| EXPECT_EQ(sync_user_settings()->GetSelectedTypes(), registered_types); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSyncSetup) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| ExpectSyncPrefsChanged(); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupSyncEverything) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "syncAllDataTypes", true); |
| ExpectHasBoolKey(dictionary, "appsRegistered", true); |
| ExpectHasBoolKey(dictionary, "autofillRegistered", true); |
| ExpectHasBoolKey(dictionary, "bookmarksRegistered", true); |
| ExpectHasBoolKey(dictionary, "extensionsRegistered", true); |
| ExpectHasBoolKey(dictionary, "passwordsRegistered", true); |
| ExpectHasBoolKey(dictionary, "paymentsRegistered", true); |
| ExpectHasBoolKey(dictionary, "preferencesRegistered", true); |
| ExpectHasBoolKey(dictionary, "readingListRegistered", true); |
| ExpectHasBoolKey(dictionary, "tabsRegistered", true); |
| ExpectHasBoolKey(dictionary, "themesRegistered", true); |
| ExpectHasBoolKey(dictionary, "typedUrlsRegistered", true); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", false); |
| ExpectHasBoolKey(dictionary, "encryptAllData", false); |
| CheckConfigDataTypeArguments(dictionary, SYNC_ALL_DATA, GetAllTypes()); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupManuallySyncAll) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_user_settings()->SetSelectedTypes(/*sync_everything=*/false, |
| /*types=*/GetAllTypes()); |
| ASSERT_FALSE(sync_user_settings()->IsSyncEverythingEnabled()); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, GetAllTypes()); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupSyncForAllTypesIndividually) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| for (syncer::UserSelectableType type : GetAllTypes()) { |
| const syncer::UserSelectableTypeSet types = {type}; |
| |
| sync_user_settings()->SetSelectedTypes(/*sync_everything=*/false, types); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| // Close the config overlay. |
| LoginUIServiceFactory::GetForProfile(profile())->LoginUIClosed( |
| handler_.get()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, types); |
| |
| // Clean up so we can loop back to display the dialog again. |
| web_ui_.ClearTrackedCalls(); |
| } |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupOldGaiaPassphraseRequired) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| const auto passphrase_time = base::Time::Now(); |
| |
| sync_user_settings()->SetPassphraseRequired(); |
| sync_user_settings()->SetPassphraseType( |
| syncer::PassphraseType::kFrozenImplicitPassphrase); |
| sync_user_settings()->SetExplicitPassphraseTime(passphrase_time); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", true); |
| ASSERT_TRUE(dictionary.contains("explicitPassphraseTime")); |
| ASSERT_TRUE(dictionary.FindString("explicitPassphraseTime")); |
| EXPECT_EQ(base::UTF16ToUTF8(base::TimeFormatShortDate(passphrase_time)), |
| *dictionary.FindString("explicitPassphraseTime")); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupCustomPassphraseRequired) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| const auto passphrase_time = base::Time::Now(); |
| |
| sync_user_settings()->SetPassphraseRequired(); |
| sync_user_settings()->SetPassphraseType( |
| syncer::PassphraseType::kCustomPassphrase); |
| sync_user_settings()->SetExplicitPassphraseTime(passphrase_time); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", true); |
| ASSERT_TRUE(dictionary.contains("explicitPassphraseTime")); |
| ASSERT_TRUE(dictionary.FindString("explicitPassphraseTime")); |
| EXPECT_EQ(base::UTF16ToUTF8(base::TimeFormatShortDate(passphrase_time)), |
| *dictionary.FindString("explicitPassphraseTime")); |
| } |
| |
| // Verifies that the user is not prompted to enter the custom passphrase while |
| // sync setup is ongoing. This isn't reachable on Ash because |
| // IsInitialSyncFeatureSetupComplete() always returns true. |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F(PeopleHandlerTest, OngoingSetupCustomPassphraseRequired) { |
| SigninUserWithoutSyncFeature(); |
| CreatePeopleHandler(); |
| |
| const auto passphrase_time = base::Time::Now(); |
| |
| sync_service_->SetSyncFeatureRequested(); |
| sync_user_settings()->SetPassphraseRequired(); |
| sync_user_settings()->SetPassphraseType( |
| syncer::PassphraseType::kCustomPassphrase); |
| sync_user_settings()->SetExplicitPassphraseTime(passphrase_time); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", false); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| TEST_F(PeopleHandlerTest, ShowSetupTrustedVaultKeysRequired) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetPassphraseType( |
| syncer::PassphraseType::kTrustedVaultPassphrase); |
| sync_service_->SetTrustedVaultKeyRequired(true); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "passphraseRequired", false); |
| ExpectHasBoolKey(dictionary, "trustedVaultKeysRequired", true); |
| EXPECT_FALSE(dictionary.contains("explicitPassphraseTime")); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupEncryptAll) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_user_settings()->SetIsUsingExplicitPassphrase(true); |
| ASSERT_TRUE(sync_user_settings()->IsEncryptEverythingEnabled()); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "encryptAllData", true); |
| } |
| |
| TEST_F(PeopleHandlerTest, ShowSetupEncryptAllDisallowed) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| sync_user_settings()->SetCustomPassphraseAllowed(false); |
| |
| // This should display the sync setup dialog (not login). |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| base::Value::Dict dictionary = ExpectSyncPrefsChanged(); |
| ExpectHasBoolKey(dictionary, "encryptAllData", false); |
| ExpectHasBoolKey(dictionary, "customPassphraseAllowed", false); |
| } |
| |
| TEST_F(PeopleHandlerTest, CannotCreatePassphraseIfCustomPassphraseDisallowed) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetCustomPassphraseAllowed(false); |
| |
| ASSERT_FALSE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append("passphrase123"); |
| handler_->HandleSetEncryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(false); |
| |
| EXPECT_FALSE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| } |
| |
| TEST_F(PeopleHandlerTest, CannotOverwritePassphraseWithNewOne) { |
| const std::string kInitialPassphrase = "initial_passphrase"; |
| |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| sync_user_settings()->SetEncryptionPassphrase(kInitialPassphrase); |
| ASSERT_TRUE(sync_user_settings()->IsUsingExplicitPassphrase()); |
| |
| base::Value::List list_args; |
| list_args.Append(kTestCallbackId); |
| list_args.Append("passphrase123"); |
| handler_->HandleSetEncryptionPassphrase(list_args); |
| |
| ExpectSetPassphraseSuccess(false); |
| |
| EXPECT_EQ(sync_user_settings()->GetEncryptionPassphrase(), |
| kInitialPassphrase); |
| } |
| |
| TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmSoon) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| ASSERT_TRUE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| sync_service_->MimicDashboardClear(); |
| sync_service_->FireStateChanged(); |
| |
| ASSERT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::INITIALIZING); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_TRUE(sync_user_settings()->IsSyncFeatureDisabledViaDashboard()); |
| #else // BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_FALSE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // Now the user confirms sync again. This should set both the sync-requested |
| // and the first-setup-complete bits. |
| base::Value::List did_abort; |
| did_abort.Append(false); |
| handler_->OnDidClosePage(did_abort); |
| |
| EXPECT_TRUE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| } |
| |
| TEST_F(PeopleHandlerTest, DashboardClearWhileSettingsOpen_ConfirmLater) { |
| SigninUserAndTurnSyncFeatureOn(); |
| CreatePeopleHandler(); |
| |
| ASSERT_TRUE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| |
| handler_->HandleShowSyncSetupUI(base::Value::List()); |
| |
| sync_service_->MimicDashboardClear(); |
| sync_service_->FireStateChanged(); |
| |
| ASSERT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::INITIALIZING); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_TRUE(sync_user_settings()->IsSyncFeatureDisabledViaDashboard()); |
| #else // BUILDFLAG(IS_CHROMEOS_ASH) |
| ASSERT_FALSE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // The user waits a while before doing anything, so sync starts up in |
| // transport mode. |
| sync_service_->SetTransportState(syncer::SyncService::TransportState::ACTIVE); |
| sync_service_->FireStateChanged(); |
| |
| // Now the user confirms sync again. This should set the sync-requested bit |
| // and also the first-setup-complete bit (except on ChromeOS Ash where it is |
| // always true). |
| base::Value::List did_abort; |
| did_abort.Append(false); |
| handler_->OnDidClosePage(did_abort); |
| |
| EXPECT_EQ(sync_service_->GetTransportState(), |
| syncer::SyncService::TransportState::ACTIVE); |
| EXPECT_TRUE(sync_user_settings()->IsInitialSyncFeatureSetupComplete()); |
| } |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| TEST(PeopleHandlerDiceTest, StoredAccountsList) { |
| ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal()); |
| content::BrowserTaskEnvironment task_environment; |
| |
| network::TestURLLoaderFactory url_loader_factory = |
| network::TestURLLoaderFactory(); |
| TestingProfile::TestingFactories factories = |
| IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| factories.push_back( |
| {ChromeSigninClientFactory::GetInstance(), |
| base::BindRepeating(&BuildChromeSigninClientWithURLLoader, |
| &url_loader_factory)}); |
| |
| TestingProfile::Builder builder; |
| builder.AddTestingFactories(factories); |
| |
| std::unique_ptr<TestingProfile> profile = builder.Build(); |
| ASSERT_EQ(true, AccountConsistencyModeManager::IsDiceEnabledForProfile( |
| profile.get())); |
| |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| identity_test_env->SetTestURLLoaderFactory(&url_loader_factory); |
| |
| auto account_1 = identity_test_env->MakeAccountAvailable( |
| "a@gmail.com", {.set_cookie = true}); |
| auto account_2 = identity_test_env->MakeAccountAvailable( |
| "b@gmail.com", {.set_cookie = true}); |
| identity_test_env->SetPrimaryAccount(account_1.email, |
| signin::ConsentLevel::kSignin); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List accounts = handler.GetStoredAccountsList(); |
| |
| ASSERT_EQ(2u, accounts.size()); |
| ASSERT_TRUE(accounts[0].GetDict().FindString("email")); |
| ASSERT_TRUE(accounts[1].GetDict().FindString("email")); |
| EXPECT_EQ("a@gmail.com", *accounts[0].GetDict().FindString("email")); |
| EXPECT_EQ("b@gmail.com", *accounts[1].GetDict().FindString("email")); |
| } |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| TEST(PeopleHandlerMainProfile, Signout) { |
| content::BrowserTaskEnvironment task_environment; |
| |
| TestingProfile::Builder builder; |
| builder.SetIsMainProfile(true); |
| |
| std::unique_ptr<TestingProfile> profile = |
| IdentityTestEnvironmentProfileAdaptor:: |
| CreateProfileForIdentityTestEnvironment(builder); |
| |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| auto* identity_manager = identity_test_env->identity_manager(); |
| |
| identity_test_env->MakePrimaryAccountAvailable("user@gmail.com", |
| ConsentLevel::kSync); |
| ASSERT_TRUE(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); |
| |
| identity_test_env->MakeAccountAvailable("a@gmail.com"); |
| EXPECT_EQ(2U, identity_manager->GetAccountsWithRefreshTokens().size()); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| handler.HandleSignout(args); |
| |
| EXPECT_FALSE(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager->HasPrimaryAccount(ConsentLevel::kSignin)); |
| // Signout should only revoke sync consent and not change any accounts. |
| EXPECT_EQ(2U, identity_manager->GetAccountsWithRefreshTokens().size()); |
| } |
| |
| #if DCHECK_IS_ON() |
| TEST(PeopleHandlerMainProfile, DeleteProfileCrashes) { |
| content::BrowserTaskEnvironment task_environment; |
| |
| TestingProfile::Builder builder; |
| builder.SetIsMainProfile(true); |
| |
| std::unique_ptr<TestingProfile> profile = |
| IdentityTestEnvironmentProfileAdaptor:: |
| CreateProfileForIdentityTestEnvironment(builder); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List args; |
| args.Append(/*delete_profile=*/true); |
| EXPECT_DEATH(handler.HandleSignout(args), ".*"); |
| } |
| #endif // DCHECK_IS_ON() |
| |
| TEST(PeopleHandlerSecondaryProfile, SignoutWhenSyncing) { |
| content::BrowserTaskEnvironment task_environment; |
| |
| TestingProfile::Builder builder; |
| builder.SetIsMainProfile(false); |
| |
| std::unique_ptr<TestingProfile> profile = |
| IdentityTestEnvironmentProfileAdaptor:: |
| CreateProfileForIdentityTestEnvironment(builder); |
| |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| auto* identity_manager = identity_test_env->identity_manager(); |
| |
| auto account_1 = identity_test_env->MakeAccountAvailable("a@gmail.com"); |
| auto account_2 = identity_test_env->MakeAccountAvailable("b@gmail.com"); |
| identity_test_env->SetPrimaryAccount(account_1.email, |
| signin::ConsentLevel::kSync); |
| EXPECT_EQ(2U, identity_manager->GetAccountsWithRefreshTokens().size()); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| handler.HandleSignout(args); |
| EXPECT_FALSE(identity_manager->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_FALSE(identity_manager->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_TRUE(identity_manager->GetAccountsWithRefreshTokens().empty()); |
| } |
| |
| TEST(PeopleHandlerMainProfile, GetStoredAccountsList) { |
| content::BrowserTaskEnvironment task_environment; |
| |
| network::TestURLLoaderFactory url_loader_factory = |
| network::TestURLLoaderFactory(); |
| TestingProfile::TestingFactories factories = |
| IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| factories.push_back( |
| {ChromeSigninClientFactory::GetInstance(), |
| base::BindRepeating(&BuildChromeSigninClientWithURLLoader, |
| &url_loader_factory)}); |
| |
| TestingProfile::Builder builder; |
| builder.SetIsMainProfile(true); |
| builder.AddTestingFactories(factories); |
| |
| std::unique_ptr<TestingProfile> profile = |
| IdentityTestEnvironmentProfileAdaptor:: |
| CreateProfileForIdentityTestEnvironment(builder); |
| |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| identity_test_env->SetTestURLLoaderFactory(&url_loader_factory); |
| auto* identity_manager = identity_test_env->identity_manager(); |
| |
| identity_test_env->MakePrimaryAccountAvailable("user@gmail.com", |
| ConsentLevel::kSignin); |
| ASSERT_TRUE(identity_manager->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| identity_test_env->MakeAccountAvailable("a@gmail.com", {.set_cookie = true}); |
| EXPECT_EQ(2U, identity_manager->GetAccountsWithRefreshTokens().size()); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List accounts = handler.GetStoredAccountsList(); |
| |
| ASSERT_EQ(1u, accounts.size()); |
| ASSERT_TRUE(accounts[0].GetDict().FindString("email")); |
| EXPECT_EQ("user@gmail.com", *accounts[0].GetDict().FindString("email")); |
| } |
| |
| TEST(PeopleHandlerSecondaryProfile, GetStoredAccountsList) { |
| ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal()); |
| content::BrowserTaskEnvironment task_environment; |
| |
| network::TestURLLoaderFactory url_loader_factory = |
| network::TestURLLoaderFactory(); |
| TestingProfile::TestingFactories factories = |
| IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| factories.push_back( |
| {ChromeSigninClientFactory::GetInstance(), |
| base::BindRepeating(&BuildChromeSigninClientWithURLLoader, |
| &url_loader_factory)}); |
| |
| TestingProfile::Builder builder; |
| builder.SetIsMainProfile(false); |
| builder.AddTestingFactories(factories); |
| |
| std::unique_ptr<TestingProfile> profile = |
| IdentityTestEnvironmentProfileAdaptor:: |
| CreateProfileForIdentityTestEnvironment(builder); |
| |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| identity_test_env->SetTestURLLoaderFactory(&url_loader_factory); |
| auto* identity_manager = identity_test_env->identity_manager(); |
| |
| auto account_1 = identity_test_env->MakeAccountAvailable( |
| "a@gmail.com", {.set_cookie = true}); |
| auto account_2 = identity_test_env->MakeAccountAvailable( |
| "b@gmail.com", {.set_cookie = true}); |
| identity_test_env->SetPrimaryAccount(account_2.email, |
| signin::ConsentLevel::kSignin); |
| EXPECT_EQ(2U, identity_manager->GetAccountsWithRefreshTokens().size()); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List accounts = handler.GetStoredAccountsList(); |
| |
| ASSERT_EQ(2u, accounts.size()); |
| ASSERT_TRUE(accounts[0].GetDict().FindString("email")); |
| ASSERT_TRUE(accounts[1].GetDict().FindString("email")); |
| EXPECT_EQ(account_2.email, *accounts[0].GetDict().FindString("email")); |
| EXPECT_EQ(account_1.email, *accounts[1].GetDict().FindString("email")); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Regression test for crash in guest mode. https://crbug.com/1040476 |
| TEST(PeopleHandlerGuestModeTest, GetStoredAccountsList) { |
| content::BrowserTaskEnvironment task_environment; |
| TestingProfile::Builder builder; |
| builder.SetGuestSession(); |
| std::unique_ptr<Profile> profile = builder.Build(); |
| |
| PeopleHandler handler(profile.get()); |
| base::Value::List accounts = handler.GetStoredAccountsList(); |
| EXPECT_TRUE(accounts.empty()); |
| } |
| |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| TEST_F(PeopleHandlerTest, TurnOffSync) { |
| // Simulate a user who previously turned on sync. |
| identity_test_env()->MakePrimaryAccountAvailable("user@gmail.com", |
| ConsentLevel::kSync); |
| ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| |
| CreatePeopleHandler(); |
| handler_->HandleTurnOffSync(base::Value::List()); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| base::Value::Dict status = ExpectSyncStatusChanged(); |
| ExpectHasBoolKey(status, "signedIn", false); |
| } |
| #endif // !BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| TEST_F(PeopleHandlerTest, GetStoredAccountsList) { |
| // Chrome OS sets an unconsented primary account on login. |
| identity_test_env()->MakePrimaryAccountAvailable("user@gmail.com", |
| ConsentLevel::kSignin); |
| ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| |
| CreatePeopleHandler(); |
| base::Value::List accounts = handler_->GetStoredAccountsList(); |
| ASSERT_EQ(1u, accounts.size()); |
| EXPECT_EQ("user@gmail.com", *accounts[0].GetDict().FindString("email")); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| class PeopleHandlerWithExplicitBrowserSigninTest : public PeopleHandlerTest { |
| public: |
| // Checks values returned as a response of WebUI called. |
| void ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| bool should_show_settings, |
| ChromeSigninUserChoice expected_choice, |
| const std::string& expected_signed_in_email) { |
| auto& data = *web_ui_.call_data().back(); |
| EXPECT_EQ("cr.webUIResponse", data.function_name()); |
| ASSERT_TRUE(data.arg1()->is_string()); |
| EXPECT_EQ(kTestCallbackId, data.arg1()->GetString()); |
| ASSERT_TRUE(data.arg2()->is_bool()); |
| EXPECT_TRUE(data.arg2()->GetBool()) |
| << "Callback should be resolved with a boolean indicating the success, " |
| "never rejected."; |
| ASSERT_TRUE(data.arg3()->is_dict()); |
| |
| const base::Value::Dict& dict = data.arg3()->GetDict(); |
| ExpectChromeSigninUserChoiceInfoDict( |
| dict, should_show_settings, expected_choice, expected_signed_in_email); |
| } |
| |
| // Checks values returned from firing the change event. |
| // Reads the last event. Expecting at least one event. |
| void ExpectChromeSigninUserChoiceInfoFromLastChangeEvent( |
| bool should_show_settings, |
| ChromeSigninUserChoice expected_choice, |
| const std::string& expected_signed_in_email) { |
| auto values_list = GetAllFiredValuesForEventName( |
| kChromeSigninUserChoiceInfoChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]); |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| |
| const base::Value::Dict& values_dict = values_list[last_index]->GetDict(); |
| ExpectChromeSigninUserChoiceInfoDict(values_dict, should_show_settings, |
| expected_choice, |
| expected_signed_in_email); |
| } |
| |
| // Tests the Dict content returned for the WebUI for |
| // ChromeSigninUserChoiceInfo. |
| static void ExpectChromeSigninUserChoiceInfoDict( |
| const base::Value::Dict& values_dict, |
| bool expected_should_show_settings, |
| ChromeSigninUserChoice expected_choice, |
| const std::string& expected_signed_in_email) { |
| std::optional<bool> should_show_settings = |
| values_dict.FindBool("shouldShowSettings"); |
| ASSERT_TRUE(should_show_settings.has_value()); |
| EXPECT_EQ(should_show_settings.value(), expected_should_show_settings); |
| |
| std::optional<int> choice_int = values_dict.FindInt("choice"); |
| ASSERT_TRUE(choice_int.has_value()); |
| EXPECT_EQ(static_cast<ChromeSigninUserChoice>(choice_int.value()), |
| expected_choice); |
| |
| const std::string* signed_in_email = |
| values_dict.FindString("signedInEmail"); |
| ASSERT_TRUE(signed_in_email); |
| EXPECT_EQ(*signed_in_email, expected_signed_in_email); |
| } |
| |
| bool HasChromeSigninUserChoiceInfoChangeEvent() { |
| return !GetAllFiredValuesForEventName( |
| kChromeSigninUserChoiceInfoChangeEventName) |
| .empty(); |
| } |
| |
| void SetExplicitSignin(bool value) { |
| profile()->GetPrefs()->SetBoolean(prefs::kExplicitBrowserSignin, value); |
| } |
| |
| void TriggerPrimaryAccountInPersistentError() { |
| ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| |
| // Inject the error. |
| identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( |
| identity_manager()->GetPrimaryAccountId(ConsentLevel::kSignin), |
| GoogleServiceAuthError::FromInvalidGaiaCredentialsReason( |
| GoogleServiceAuthError::InvalidGaiaCredentialsReason:: |
| CREDENTIALS_REJECTED_BY_CLIENT)); |
| } |
| |
| bool HasSyncStatusUpdateChangedEvent() { |
| return !GetAllFiredValuesForEventName(kSyncStatusChangeEventName).empty(); |
| } |
| |
| void SimluateReauth() { |
| ASSERT_TRUE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); |
| |
| // Clear the error. |
| identity_test_env()->UpdatePersistentErrorOfRefreshTokenForAccount( |
| identity_manager()->GetPrimaryAccountId(ConsentLevel::kSignin), |
| GoogleServiceAuthError::AuthErrorNone()); |
| } |
| |
| void SimulateSignout() { |
| ASSERT_TRUE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); |
| |
| identity_test_env()->ClearPrimaryAccount(); |
| } |
| |
| void SimulateHandleGetChromeSigninUserChoiceInfo() const { |
| base::Value::List args_get; |
| args_get.Append(kTestCallbackId); |
| handler_->HandleGetChromeSigninUserChoiceInfo(args_get); |
| } |
| |
| void SimulateHandleSetChromeSigninUserChoiceInfo( |
| std::string_view email, |
| ChromeSigninUserChoice user_choice) { |
| base::Value::List args_set; |
| args_set.Append(static_cast<int>(user_choice)); |
| args_set.Append(email); |
| handler_->HandleSetChromeSigninUserChoice(args_set); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| switches::kExplicitBrowserSigninUIOnDesktop}; |
| }; |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, ChromeSigninUserChoice) { |
| base::HistogramTester histogram_tester; |
| |
| CreatePeopleHandler(); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| false, ChromeSigninUserChoice::kNoChoice, ""); |
| |
| std::string email("user@gmail.com"); |
| identity_test_env()->MakePrimaryAccountAvailable(email, |
| ConsentLevel::kSignin); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| true, ChromeSigninUserChoice::kNoChoice, email); |
| |
| ChromeSigninUserChoice user_choice = ChromeSigninUserChoice::kSignin; |
| SimulateHandleSetChromeSigninUserChoiceInfo(email, user_choice); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse(true, user_choice, email); |
| |
| DestroyPeopleHandler(); |
| |
| histogram_tester.ExpectTotalCount( |
| "Signin.Settings.ChromeSigninSettingModification", 1); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Settings.ChromeSigninSettingModification", |
| /*`ChromeSigninSettingModification::kToSignin`*/ 2, 1); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserAvailableOnExplicitChromeSigninSignout) { |
| const std::string email("user@gmail.com"); |
| identity_test_env()->MakePrimaryAccountAvailable(email, |
| ConsentLevel::kSignin); |
| SetExplicitSignin(true); |
| |
| CreatePeopleHandler(); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| true, ChromeSigninUserChoice::kNoChoice, email); |
| |
| SimulateSignout(); |
| |
| ASSERT_FALSE( |
| identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSignin)); |
| ASSERT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| false, ChromeSigninUserChoice::kNoChoice, ""); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserAvailableOnDiceSignin) { |
| const std::string email("user@gmail.com"); |
| identity_test_env()->MakePrimaryAccountAvailable(email, |
| ConsentLevel::kSignin); |
| // Simulates Dice signin. |
| SetExplicitSignin(false); |
| |
| CreatePeopleHandler(); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| false, ChromeSigninUserChoice::kNoChoice, email); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserInfoUpdateOnPrefValueChange) { |
| const std::string email("user@gmail.com"); |
| AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| email, ConsentLevel::kSignin); |
| SetExplicitSignin(true); |
| |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasChromeSigninUserChoiceInfoChangeEvent()); |
| |
| SigninPrefs signin_prefs(*profile()->GetPrefs()); |
| auto new_choice_value = ChromeSigninUserChoice::kSignin; |
| ASSERT_NE( |
| signin_prefs.GetChromeSigninInterceptionUserChoice(account_info.gaia), |
| new_choice_value); |
| signin_prefs.SetChromeSigninInterceptionUserChoice(account_info.gaia, |
| new_choice_value); |
| ExpectChromeSigninUserChoiceInfoFromLastChangeEvent(true, new_choice_value, |
| email); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserInfoUpdateOnSignin) { |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasChromeSigninUserChoiceInfoChangeEvent()); |
| |
| const std::string email("user@gmail.com"); |
| // Explicit browser signin. |
| identity_test_env()->MakePrimaryAccountAvailable(email, |
| ConsentLevel::kSignin); |
| |
| // By default no choice yet. |
| ExpectChromeSigninUserChoiceInfoFromLastChangeEvent( |
| true, ChromeSigninUserChoice::kNoChoice, email); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserInfoUpdateOnSync) { |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasChromeSigninUserChoiceInfoChangeEvent()); |
| |
| const std::string email("user@gmail.com"); |
| // Sync is a form of explicit browser signin. |
| identity_test_env()->MakePrimaryAccountAvailable(email, ConsentLevel::kSync); |
| |
| // By default no choice yet. |
| ExpectChromeSigninUserChoiceInfoFromLastChangeEvent( |
| true, ChromeSigninUserChoice::kNoChoice, email); |
| } |
| |
| // This test does not use `PeopleHandlerWithExplicitBrowserSigninTest` test |
| // suite and needs it's own test setup because in order to get the proper web |
| // signin, we need to set a cookie while signing in, which requires setting up a |
| // `TestURLLoaderFactory` with the `ChromeSigninClient`. |
| TEST(PeopleHandlerWebOnlySigninTest, ChromeSigninUserAvailableOnWebSignin) { |
| base::test::ScopedFeatureList scoped_feature_list{ |
| switches::kExplicitBrowserSigninUIOnDesktop}; |
| |
| // -- Test Setup start |
| |
| // Needed to enable setting a proper account signed in on the web. |
| ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal()); |
| content::BrowserTaskEnvironment task_environment; |
| |
| network::TestURLLoaderFactory url_loader_factory = |
| network::TestURLLoaderFactory(); |
| TestingProfile::TestingFactories factories = |
| IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| factories.push_back( |
| {ChromeSigninClientFactory::GetInstance(), |
| base::BindRepeating(&BuildChromeSigninClientWithURLLoader, |
| &url_loader_factory)}); |
| |
| TestingProfile::Builder builder; |
| builder.AddTestingFactories(factories); |
| std::unique_ptr<TestingProfile> profile = builder.Build(); |
| auto identity_test_env_adaptor = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile.get()); |
| // This test env should be used throughout the test. |
| auto* identity_test_env = identity_test_env_adaptor->identity_test_env(); |
| identity_test_env->SetTestURLLoaderFactory(&url_loader_factory); |
| |
| PeopleHandler handler(profile.get()); |
| |
| // -- Test Setup end. |
| |
| // Test before web signin -- only need to check the `shouldShowSettings` param |
| { |
| base::Value::Dict chrome_signin_user_choice_info_dict = |
| handler.GetChromeSigninUserChoiceInfo(); |
| std::optional<bool> should_show_settings = |
| chrome_signin_user_choice_info_dict.FindBool("shouldShowSettings"); |
| ASSERT_TRUE(should_show_settings.has_value()); |
| EXPECT_FALSE(should_show_settings.value()); |
| } |
| |
| const std::string email("user@gmail.com"); |
| // Signs in to the web only. |
| identity_test_env->MakeAccountAvailable(email, {.set_cookie = true}); |
| ASSERT_FALSE(identity_test_env->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| // Test after web signin and check all the fields. |
| { |
| base::Value::Dict chrome_signin_user_choice_info_dict = |
| handler.GetChromeSigninUserChoiceInfo(); |
| PeopleHandlerWithExplicitBrowserSigninTest:: |
| ExpectChromeSigninUserChoiceInfoDict( |
| chrome_signin_user_choice_info_dict, |
| /*expected_should_show_settings=*/true, |
| ChromeSigninUserChoice::kNoChoice, email); |
| } |
| |
| // Check that `SignedInState` is properly computed |
| { |
| const base::Value::Dict& sync_status_values = |
| handler.GetSyncStatusDictionary(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::WebOnlySignedIn); |
| } |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, SigninPausedThenSignout) { |
| identity_test_env()->MakePrimaryAccountAvailable(kTestUser, |
| ConsentLevel::kSignin); |
| SetExplicitSignin(true); |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasSyncStatusUpdateChangedEvent()); |
| |
| TriggerPrimaryAccountInPersistentError(); |
| |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::SignedInPaused); |
| } |
| |
| // Simulates pressing on the "Sign out" Button in the Sign in Paused state, |
| // that redirects to `PeopleHandler::HandleSignout()`. Since the test has no |
| // browser, clearing the primary account should be equivalent. |
| SimulateSignout(); |
| |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::SignedOut); |
| } |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, SigninPausedThenReauth) { |
| identity_test_env()->MakePrimaryAccountAvailable(kTestUser, |
| ConsentLevel::kSignin); |
| SetExplicitSignin(true); |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasSyncStatusUpdateChangedEvent()); |
| |
| TriggerPrimaryAccountInPersistentError(); |
| |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::SignedInPaused); |
| ; |
| } |
| |
| // Simulates pressing on the "Verify it's you" button in the Sign in Paused |
| // state, and reauth. |
| SimluateReauth(); |
| |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::SignedIn); |
| } |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, SigninPausedValueWithSync) { |
| CreatePeopleHandler(); |
| |
| ASSERT_FALSE(HasSyncStatusUpdateChangedEvent()); |
| |
| // User is syncing. |
| identity_test_env()->MakePrimaryAccountAvailable(kTestUser, |
| ConsentLevel::kSync); |
| |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::Syncing); |
| } |
| |
| // Invalidate the account while it is syncing. |
| TriggerPrimaryAccountInPersistentError(); |
| |
| // `signinPaused` is still false even when the account is in error. |
| { |
| auto values_list = |
| GetAllFiredValuesForEventName(kSyncStatusChangeEventName); |
| ASSERT_GT(values_list.size(), 0U); |
| size_t last_index = values_list.size() - 1; |
| ASSERT_TRUE(values_list[last_index]->is_dict()); |
| const base::Value::Dict& sync_status_values = |
| values_list[last_index]->GetDict(); |
| std::optional<int> signedInState = |
| sync_status_values.FindInt("signedInState"); |
| ASSERT_TRUE(signedInState.has_value()); |
| EXPECT_EQ(static_cast<SignedInState>(signedInState.value()), |
| SignedInState::Syncing); |
| } |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserChoiceHistogramsWhenSignedOut) { |
| base::HistogramTester histogram_tester; |
| CreatePeopleHandler(); |
| |
| // Simluates settings page loading. |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| |
| // Simulates closing the settings page. |
| DestroyPeopleHandler(); |
| |
| // No account are signed in, the setting is not expected to be shown, so no |
| // values related to it should be recorded. |
| histogram_tester.ExpectTotalCount( |
| "Signin.Settings.ChromeSigninSettingModification", 0); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserChoiceHistogramsWhenSignedInWithoutChangingSetting) { |
| base::HistogramTester histogram_tester; |
| // Signed in user can see the setting. |
| identity_test_env()->MakePrimaryAccountAvailable("email@gmail.com", |
| ConsentLevel::kSignin); |
| CreatePeopleHandler(); |
| |
| // Simluates settings page loading. |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| |
| // Simulates closing the settings page. |
| DestroyPeopleHandler(); |
| |
| // Setting is seen but not modiffied. |
| histogram_tester.ExpectTotalCount( |
| "Signin.Settings.ChromeSigninSettingModification", 1); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Settings.ChromeSigninSettingModification", |
| /*`ChromeSigninSettingModification::kNoModification`*/ 0, 1); |
| } |
| |
| TEST_F(PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserChoiceHistogramsWhenSignedInWithChangingSetting) { |
| base::HistogramTester histogram_tester; |
| // Signed in user can see the setting. |
| AccountInfo account = identity_test_env()->MakePrimaryAccountAvailable( |
| /*email=*/"email@gmail.com", ConsentLevel::kSignin); |
| |
| CreatePeopleHandler(); |
| |
| // Simluates settings page loading. |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| |
| ChromeSigninUserChoice current_choice = |
| SigninPrefs(*profile()->GetPrefs()) |
| .GetChromeSigninInterceptionUserChoice(account.gaia); |
| |
| // Simulates setting a new value through the UI. |
| ChromeSigninUserChoice user_choice = ChromeSigninUserChoice::kSignin; |
| ASSERT_NE(current_choice, user_choice); |
| SimulateHandleSetChromeSigninUserChoiceInfo(account.email, user_choice); |
| |
| // Simulates a second selection within the same settings session. |
| ChromeSigninUserChoice user_choice2 = ChromeSigninUserChoice::kDoNotSignin; |
| ASSERT_NE(current_choice, user_choice2); |
| SimulateHandleSetChromeSigninUserChoiceInfo(account.email, user_choice2); |
| |
| // Enforcing changing the value to the same previous one should not record a |
| // new modification. |
| SimulateHandleSetChromeSigninUserChoiceInfo(account.email, user_choice2); |
| |
| // Simulates closing the settings page. |
| DestroyPeopleHandler(); |
| |
| // Setting is seen and modified twice. |
| histogram_tester.ExpectTotalCount( |
| "Signin.Settings.ChromeSigninSettingModification", 2); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Settings.ChromeSigninSettingModification", |
| /*`ChromeSigninSettingModification::kToSignin`*/ 2, 1); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Settings.ChromeSigninSettingModification", |
| /*`ChromeSigninSettingModification::kToDoNotSignin`*/ 3, 1); |
| } |
| |
| TEST_F( |
| PeopleHandlerWithExplicitBrowserSigninTest, |
| ChromeSigninUserChoiceHistogramsWhenSignedInWithChangingSettingThenSignout) { |
| base::HistogramTester histogram_tester; |
| // Signed in user can see the setting. |
| AccountInfo account = identity_test_env()->MakePrimaryAccountAvailable( |
| /*email=*/"email@gmail.com", ConsentLevel::kSignin); |
| |
| CreatePeopleHandler(); |
| |
| // Simluates settings page loading. |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| |
| SigninPrefs signin_prefs(*profile()->GetPrefs()); |
| ChromeSigninUserChoice current_choice = |
| signin_prefs.GetChromeSigninInterceptionUserChoice(account.gaia); |
| |
| // Simulates setting a new value through the settings UI. |
| ChromeSigninUserChoice new_value = ChromeSigninUserChoice::kSignin; |
| ASSERT_NE(current_choice, new_value); |
| SimulateHandleSetChromeSigninUserChoiceInfo(account.email, new_value); |
| |
| SimulateSignout(); |
| |
| SimulateHandleGetChromeSigninUserChoiceInfo(); |
| // The setting should not be seen anymore. |
| ExpectChromeSigninUserChoiceInfoFromWebUiResponse( |
| false, ChromeSigninUserChoice::kNoChoice, ""); |
| |
| // Simulates closing the settings page. |
| DestroyPeopleHandler(); |
| |
| // A modification value is still recorded, even after signing out, since a |
| // modification occurred during the session. |
| histogram_tester.ExpectTotalCount( |
| "Signin.Settings.ChromeSigninSettingModification", 1); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Settings.ChromeSigninSettingModification", |
| /*`ChromeSigninSettingModification::kToSignin`*/ 2, 1); |
| } |
| |
| #endif |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS) |
| class PeopleHandlerSignoutTest : public BrowserWithTestWindowTest { |
| public: |
| PeopleHandlerSignoutTest() = default; |
| ~PeopleHandlerSignoutTest() override = default; |
| |
| signin::IdentityTestEnvironment* identity_test_env() { |
| return identity_test_env_profile_adaptor_->identity_test_env(); |
| } |
| |
| signin::IdentityManager* identity_manager() { |
| return identity_test_env()->identity_manager(); |
| } |
| |
| PeopleHandler* handler() { return handler_.get(); } |
| |
| void CreatePeopleHandler() { |
| handler_ = std::make_unique<TestingPeopleHandler>(&web_ui_, profile()); |
| } |
| |
| void SimulateSignout(const base::Value::List& args) { |
| handler()->HandleSignout(args); |
| } |
| |
| content::WebUI* web_ui() { return handler()->web_ui(); } |
| |
| content::WebContents* web_contents() { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| protected: |
| // testing::Test: |
| void SetUp() override { |
| BrowserWithTestWindowTest::SetUp(); |
| |
| identity_test_env_profile_adaptor_ = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile()); |
| |
| // Create the first tab so that web_contents() exists. |
| AddTab(browser(), GURL(chrome::kChromeUINewTabURL)); |
| web_ui_.set_web_contents(web_contents()); |
| } |
| |
| SigninClient* GetSigninSlient(Profile* profile) { |
| return ChromeSigninClientFactory::GetForProfile(profile); |
| } |
| |
| private: |
| TestingProfile::TestingFactories GetTestingFactories() override { |
| return IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| } |
| |
| void TearDown() override { |
| handler_->set_web_ui(nullptr); |
| handler_->DisallowJavascript(); |
| identity_test_env_profile_adaptor_.reset(); |
| BrowserWithTestWindowTest::TearDown(); |
| } |
| |
| std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> |
| identity_test_env_profile_adaptor_; |
| content::TestWebUI web_ui_; |
| std::unique_ptr<TestingPeopleHandler> handler_; |
| }; |
| |
| #if DCHECK_IS_ON() |
| TEST_F(PeopleHandlerSignoutTest, RevokeSyncNotAllowed) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSync); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| GetSigninSlient(profile())->set_is_clear_primary_account_allowed_for_testing( |
| SigninClient::SignoutDecision::REVOKE_SYNC_DISALLOWED); |
| |
| CreatePeopleHandler(); |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| EXPECT_DEATH(SimulateSignout(args), ".*"); |
| } |
| |
| TEST_F(PeopleHandlerSignoutTest, SignoutNotAllowedSyncOff) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSignin); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| GetSigninSlient(profile())->set_is_clear_primary_account_allowed_for_testing( |
| SigninClient::SignoutDecision::CLEAR_PRIMARY_ACCOUNT_DISALLOWED); |
| |
| CreatePeopleHandler(); |
| |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| EXPECT_DEATH(SimulateSignout(args), ".*"); |
| } |
| #endif // DCHECK_IS_ON() |
| |
| TEST_F(PeopleHandlerSignoutTest, SignoutNotAllowedSyncOn) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSync); |
| auto account_2 = identity_test_env()->MakeAccountAvailable("b@gmail.com"); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_EQ(2U, identity_manager()->GetAccountsWithRefreshTokens().size()); |
| GetSigninSlient(profile())->set_is_clear_primary_account_allowed_for_testing( |
| SigninClient::SignoutDecision::CLEAR_PRIMARY_ACCOUNT_DISALLOWED); |
| EXPECT_TRUE(ChromeSigninClientFactory::GetForProfile(profile()) |
| ->IsRevokeSyncConsentAllowed()); |
| |
| CreatePeopleHandler(); |
| |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| SimulateSignout(args); |
| |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_EQ(2U, identity_manager()->GetAccountsWithRefreshTokens().size()); |
| |
| // Signout not triggered on dice platforms. |
| EXPECT_EQ(web_contents()->GetVisibleURL().spec(), chrome::kChromeUINewTabURL); |
| EXPECT_NE(web_contents()->GetVisibleURL(), |
| GaiaUrls::GetInstance()->service_logout_url()); |
| } |
| |
| TEST_F(PeopleHandlerSignoutTest, SignoutWithSyncOff) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSignin); |
| auto account_2 = identity_test_env()->MakeAccountAvailable("b@gmail.com"); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_EQ(2U, identity_manager()->GetAccountsWithRefreshTokens().size()); |
| |
| CreatePeopleHandler(); |
| |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| SimulateSignout(args); |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| EXPECT_EQ(web_contents()->GetVisibleURL(), |
| GaiaUrls::GetInstance()->service_logout_url()); |
| #else |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| } |
| |
| TEST_F(PeopleHandlerSignoutTest, SignoutWithSyncOn) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSync); |
| auto account_2 = identity_test_env()->MakeAccountAvailable("b@gmail.com"); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_EQ(2U, identity_manager()->GetAccountsWithRefreshTokens().size()); |
| |
| CreatePeopleHandler(); |
| |
| EXPECT_NE(web_ui(), nullptr); |
| EXPECT_NE(nullptr, web_ui()->GetWebContents()); |
| |
| EXPECT_TRUE(chrome::FindBrowserWithTab(web_ui()->GetWebContents())); |
| |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| SimulateSignout(args); |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| EXPECT_EQ(web_contents()->GetVisibleURL(), |
| GaiaUrls::GetInstance()->service_logout_url()); |
| #else |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_TRUE(identity_manager()->GetAccountsWithRefreshTokens().empty()); |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| } |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| #if BUILDFLAG(ENABLE_DICE_SUPPORT) |
| class ExplicitBrowserSigninPeopleHandlerSignoutTest |
| : public PeopleHandlerSignoutTest { |
| private: |
| base::test::ScopedFeatureList features_{ |
| switches::kExplicitBrowserSigninUIOnDesktop}; |
| }; |
| |
| TEST_F(ExplicitBrowserSigninPeopleHandlerSignoutTest, Signout) { |
| auto account_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "a@gmail.com", ConsentLevel::kSignin); |
| auto account_2 = identity_test_env()->MakeAccountAvailable("b@gmail.com"); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| EXPECT_EQ(2U, identity_manager()->GetAccountsWithRefreshTokens().size()); |
| |
| CreatePeopleHandler(); |
| |
| base::Value::List args; |
| args.Append(/*delete_profile=*/false); |
| SimulateSignout(args); |
| EXPECT_EQ(web_contents()->GetVisibleURL(), |
| GaiaUrls::GetInstance()->LogOutURLWithContinueURL(GURL())); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); |
| } |
| #endif // BUILDFLAG(ENABLE_DICE_SUPPORT) |
| } // namespace settings |