blob: 8a79f0d2494788af32be69f15b5a13a3b6192872 [file] [log] [blame]
// Copyright 2022 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/startup/first_run_service.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/raw_ref.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_metrics.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/signin/signin_features.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/profile_picker.h"
#include "chrome/browser/ui/profile_ui_test_utils.h"
#include "chrome/browser/ui/signin/profile_customization_util.h"
#include "chrome/browser/ui/startup/first_run_test_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/metrics/metrics_service.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_metrics.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/primary_account_mutator.h"
#include "components/variations/synthetic_trials_active_group_id_provider.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "google_apis/gaia/core_account_id.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/webview/webview.h"
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/device_settings_lacros.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/device_settings_service.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#endif
namespace {
class PolicyUpdateObserver : public policy::PolicyService::Observer {
public:
PolicyUpdateObserver(policy::PolicyService& policy_service,
base::OnceClosure policy_updated_callback)
: policy_service_(policy_service),
policy_updated_callback_(std::move(policy_updated_callback)) {
DCHECK(policy_updated_callback_);
policy_service_->AddObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
this);
}
~PolicyUpdateObserver() override {
policy_service_->RemoveObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
this);
}
void OnPolicyUpdated(const policy::PolicyNamespace& ns,
const policy::PolicyMap& previous,
const policy::PolicyMap& current) override {
if (ns.domain != policy::PolicyDomain::POLICY_DOMAIN_CHROME) {
return;
}
policy_service_->RemoveObserver(policy::PolicyDomain::POLICY_DOMAIN_CHROME,
this);
std::move(policy_updated_callback_).Run();
}
const raw_ref<policy::PolicyService> policy_service_;
base::OnceClosure policy_updated_callback_;
};
// Converts JSON string to `base::Value` object.
static base::Value GetJSONAsValue(base::StringPiece json) {
std::string error;
auto value = JSONStringValueDeserializer(json).Deserialize(nullptr, &error);
EXPECT_EQ("", error);
return base::Value::FromUniquePtrValue(std::move(value));
}
} // namespace
class FirstRunServiceBrowserTest : public FirstRunServiceBrowserTestBase {
public:
void SetUpOnMainThread() override {
FirstRunServiceBrowserTestBase::SetUpOnMainThread();
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
identity_test_env()->SetRefreshTokenForPrimaryAccount();
#endif
}
void TearDownOnMainThread() override { identity_test_env_adaptor_.reset(); }
void SetUpInProcessBrowserTestFixture() override {
create_services_subscription_ =
BrowserContextDependencyManager::GetInstance()
->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
&FirstRunServiceBrowserTest::OnWillCreateBrowserContextServices,
base::Unretained(this)));
}
signin::IdentityTestEnvironment* identity_test_env() {
return identity_test_env_adaptor_->identity_test_env();
}
protected:
void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
IdentityTestEnvironmentProfileAdaptor::
SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
}
private:
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
base::CallbackListSubscription create_services_subscription_;
// TODO(https://crbug.com/1324886): Needed because SyncService startup hangs
// otherwise. Find a way to get it not to hang instead?
profiles::testing::ScopedNonEnterpriseDomainSetterForTesting
non_enterprise_domain_setter_;
};
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
OpenFirstRunIfNeededOpensPicker) {
base::HistogramTester histogram_tester;
base::test::TestFuture<bool> proceed_future;
bool expected_fre_finished = true;
bool expected_proceed = false;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
expected_fre_finished = false; // QuitEarly
#else
expected_proceed = kForYouFreCloseShouldProceed.Get();
#endif
ASSERT_TRUE(fre_service()->ShouldOpenFirstRun());
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
proceed_future.GetCallback());
profiles::testing::WaitForPickerWidgetCreated();
EXPECT_FALSE(GetFirstRunFinishedPrefValue());
histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.ServiceCreated",
true, 1);
#if BUILDFLAG(IS_CHROMEOS_LACROS)
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunEntryPoint",
FirstRunService::EntryPoint::kOther, 1);
#endif
histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.EntryPoint",
FirstRunService::EntryPoint::kOther, 1);
// We don't expect synthetic trials to be registered here, since no group
// is configured with the feature. For the positive test case, see
// `FirstRunServiceCohortBrowserTest.GroupRegisteredAfterFre`.
PrefService* local_state = g_browser_process->local_state();
EXPECT_FALSE(local_state->HasPrefPath(prefs::kFirstRunStudyGroup));
EXPECT_FALSE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
ProfilePicker::Hide();
EXPECT_EQ(expected_proceed, proceed_future.Get());
EXPECT_EQ(expected_fre_finished, GetFirstRunFinishedPrefValue());
EXPECT_NE(expected_fre_finished, fre_service()->ShouldOpenFirstRun());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
histogram_tester.ExpectTotalCount(
"Profile.LacrosPrimaryProfileFirstRunOutcome", 0);
histogram_tester.ExpectUniqueSample(
"ProfilePicker.FirstRun.ExitStatus",
ProfilePicker::FirstRunExitStatus::kQuitEarly, 1);
histogram_tester.ExpectTotalCount("ProfilePicker.FirstRun.FinishReason", 0);
#elif BUILDFLAG(ENABLE_DICE_SUPPORT)
histogram_tester.ExpectUniqueSample(
"Signin.SignIn.Offered",
signin_metrics::AccessPoint::ACCESS_POINT_FOR_YOU_FRE, 1);
histogram_tester.ExpectTotalCount("Signin.SignIn.Started", 0);
histogram_tester.ExpectUniqueSample(
"ProfilePicker.FirstRun.ExitStatus",
ProfilePicker::FirstRunExitStatus::kQuitAtEnd, 1);
histogram_tester.ExpectUniqueSample("ProfilePicker.FirstRun.FinishReason",
/*kFinishedFlow*/ 1, 1);
#endif
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
OpenFirstRunIfNeededCalledTwice) {
// When `OpenFirstRunIfNeeded` is called twice, the callback passed to it the
// first time should be aborted (called with false) and replaced by the
// callback passed to it the second time, which will be later called with
// true on DICE and false on Lacros because it will quit early in the process.
base::test::TestFuture<bool> first_proceed_future;
base::test::TestFuture<bool> second_proceed_future;
base::HistogramTester histogram_tester;
ASSERT_TRUE(fre_service()->ShouldOpenFirstRun());
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
first_proceed_future.GetCallback());
profiles::testing::WaitForPickerWidgetCreated();
bool expected_second_proceed = true;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
expected_second_proceed = false;
#endif
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
second_proceed_future.GetCallback());
EXPECT_FALSE(first_proceed_future.Get());
histogram_tester.ExpectBucketCount(
"ProfilePicker.FirstRun.ExitStatus",
ProfilePicker::FirstRunExitStatus::kAbortTask, 1);
ProfilePicker::Hide();
profiles::testing::WaitForPickerClosed();
EXPECT_EQ(expected_second_proceed, second_proceed_future.Get());
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
FinishedSilentlyAlreadySyncing) {
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
CoreAccountId account_id =
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
ASSERT_FALSE(account_id.empty());
identity_manager->GetPrimaryAccountMutator()->SetPrimaryAccount(
account_id, signin::ConsentLevel::kSync);
base::HistogramTester histogram_tester;
ASSERT_TRUE(profile()->IsMainProfile());
EXPECT_TRUE(ShouldOpenFirstRun(profile()));
ASSERT_TRUE(fre_service());
// The FRE should be finished silently during the creation of the service.
EXPECT_TRUE(GetFirstRunFinishedPrefValue());
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedAlreadySyncing, 1);
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
FinishedSilentlySyncConsentDisabled) {
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
base::HistogramTester histogram_tester;
profile()->GetPrefs()->SetBoolean(prefs::kEnableSyncConsent, false);
EXPECT_FALSE(
identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
ASSERT_TRUE(profile()->IsMainProfile());
EXPECT_TRUE(ShouldOpenFirstRun(profile()));
ASSERT_TRUE(fre_service());
// The FRE should be finished silently during the creation of the service.
EXPECT_TRUE(GetFirstRunFinishedPrefValue());
EXPECT_FALSE(ShouldOpenFirstRun(profile()));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
FinishedSilentlyIsCurrentUserEphemeral) {
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
base::HistogramTester histogram_tester;
// Setup the ephemeral for Lacros.
auto init_params = chromeos::BrowserInitParams::GetForTests()->Clone();
init_params->is_current_user_ephemeral = true;
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
ASSERT_TRUE(profile()->IsMainProfile());
EXPECT_TRUE(ShouldOpenFirstRun(profile()));
ASSERT_TRUE(fre_service());
EXPECT_TRUE(GetFirstRunFinishedPrefValue());
EXPECT_FALSE(ShouldOpenFirstRun(profile()));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
FinishedSilentlyDeviceEphemeralUsersEnabled) {
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
base::HistogramTester histogram_tester;
// The `DeviceEphemeralUsersEnabled` is read through DeviceSettings provided
// on startup.
auto init_params = chromeos::BrowserInitParams::GetForTests()->Clone();
init_params->device_settings->deprecated_device_ephemeral_users_enabled =
crosapi::mojom::DeviceSettings::OptionalBool::kTrue;
auto device_settings = init_params->device_settings.Clone();
chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
// TODO(crbug.com/1330310): Ideally this should be done as part of
// `SetInitParamsForTests()`.
g_browser_process->browser_policy_connector()
->device_settings_lacros()
->UpdateDeviceSettings(std::move(device_settings));
ASSERT_TRUE(profile()->IsMainProfile());
EXPECT_TRUE(ShouldOpenFirstRun(profile()));
ASSERT_TRUE(fre_service());
EXPECT_TRUE(GetFirstRunFinishedPrefValue());
EXPECT_FALSE(ShouldOpenFirstRun(profile()));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
class FirstRunServiceNotForYouBrowserTest : public FirstRunServiceBrowserTest {
public:
FirstRunServiceNotForYouBrowserTest() {
scoped_feature_list_.InitAndDisableFeature(kForYouFre);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(FirstRunServiceNotForYouBrowserTest,
ShouldOpenFirstRunNeverOnDice) {
// Even though the FRE could be open, we should not create the service for it.
EXPECT_TRUE(ShouldOpenFirstRun(profile()));
EXPECT_EQ(nullptr, fre_service());
}
class FirstRunServiceCohortBrowserTest : public FirstRunServiceBrowserTest {
public:
static constexpr char kStudyTestGroupName1[] = "test_group_1";
static constexpr char kStudyTestGroupName2[] = "test_group_2";
FirstRunServiceCohortBrowserTest() {
variations::SyntheticTrialsActiveGroupIdProvider::GetInstance()
->ResetForTesting();
scoped_feature_list_.InitWithFeaturesAndParameters(
{
{kForYouFreSyntheticTrialRegistration,
{{"group_name", kStudyTestGroupName1}}},
{kForYouFre, {}},
},
{});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(FirstRunServiceCohortBrowserTest,
PRE_GroupRegisteredAfterFre) {
EXPECT_TRUE(ShouldOpenFirstRun(browser()->profile()));
// We don't expect the synthetic trial to be registered before the FRE runs.
PrefService* local_state = g_browser_process->local_state();
EXPECT_FALSE(local_state->HasPrefPath(prefs::kFirstRunStudyGroup));
EXPECT_FALSE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
base::test::TestFuture<bool> proceed_future;
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
proceed_future.GetCallback());
// Opening the FRE triggers recording of the group.
EXPECT_EQ(kStudyTestGroupName1,
local_state->GetString(prefs::kFirstRunStudyGroup));
EXPECT_TRUE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
EXPECT_TRUE(variations::IsInSyntheticTrialGroup("ForYouFreSynthetic",
kStudyTestGroupName1));
profiles::testing::WaitForPickerWidgetCreated();
ProfilePicker::Hide();
profiles::testing::WaitForPickerClosed();
EXPECT_TRUE(proceed_future.Get());
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceCohortBrowserTest,
GroupRegisteredAfterFre) {
EXPECT_FALSE(ShouldOpenFirstRun(browser()->profile()));
PrefService* local_state = g_browser_process->local_state();
EXPECT_EQ(kStudyTestGroupName1,
local_state->GetString(prefs::kFirstRunStudyGroup));
EXPECT_TRUE(variations::IsInSyntheticTrialGroup("ForYouFreSynthetic",
kStudyTestGroupName1));
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceCohortBrowserTest,
PRE_PRE_GroupViaPrefs) {
// Setting the pref, we expect it to get picked up in an upcoming startup.
PrefService* local_state = g_browser_process->local_state();
local_state->SetString(prefs::kFirstRunStudyGroup, kStudyTestGroupName2);
EXPECT_FALSE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceCohortBrowserTest, PRE_GroupViaPrefs) {
// The synthetic group should not be registered yet since we didn't go through
// the FRE.
EXPECT_FALSE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
// Setting this should make the next run finally register the synthetic trial.
PrefService* local_state = g_browser_process->local_state();
local_state->SetBoolean(prefs::kFirstRunFinished, true);
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceCohortBrowserTest, GroupViaPrefs) {
EXPECT_TRUE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
// The registered group is read from the prefs, not from the feature param.
EXPECT_TRUE(variations::IsInSyntheticTrialGroup("ForYouFreSynthetic",
kStudyTestGroupName2));
}
class FirstRunServiceControlBrowserTest : public FirstRunServiceBrowserTest {
public:
static constexpr char kStudyTestGroupName[] = "control";
FirstRunServiceControlBrowserTest() {
variations::SyntheticTrialsActiveGroupIdProvider::GetInstance()
->ResetForTesting();
scoped_feature_list_.InitWithFeaturesAndParameters(
{
{kForYouFreSyntheticTrialRegistration,
{{"group_name", kStudyTestGroupName}}},
},
{kForYouFre});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(FirstRunServiceControlBrowserTest, PRE_Control) {
EXPECT_EQ(nullptr, FirstRunServiceFactory::GetForBrowserContext(profile()));
// The FRE is directly marked finished and we join the indicated cohort.
PrefService* local_state = g_browser_process->local_state();
EXPECT_TRUE(local_state->GetBoolean(prefs::kFirstRunFinished));
EXPECT_EQ(kStudyTestGroupName,
local_state->GetString(prefs::kFirstRunStudyGroup));
EXPECT_TRUE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
EXPECT_TRUE(variations::IsInSyntheticTrialGroup("ForYouFreSynthetic",
kStudyTestGroupName));
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceControlBrowserTest, Control) {
EXPECT_EQ(nullptr, FirstRunServiceFactory::GetForBrowserContext(profile()));
// On subsequent startups, we continue the registration.
EXPECT_TRUE(variations::HasSyntheticTrial("ForYouFreSynthetic"));
EXPECT_TRUE(variations::IsInSyntheticTrialGroup("ForYouFreSynthetic",
kStudyTestGroupName));
}
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
struct PolicyTestParam {
const std::string test_suffix;
const std::string key;
const std::string value; // As JSON string, base::Value is not copy-friendly.
const bool should_open_fre = false;
};
const PolicyTestParam kPolicyTestParams[] = {
{.key = policy::key::kSyncDisabled, .value = "true"},
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
{.key = policy::key::kBrowserSignin, .value = "0"},
{.key = policy::key::kBrowserSignin, .value = "1", .should_open_fre = true},
#if !BUILDFLAG(IS_LINUX)
{.key = policy::key::kBrowserSignin, .value = "2"},
#endif // BUILDFLAG(IS_LINUX)
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
{.key = policy::key::kPromotionalTabsEnabled, .value = "false"},
};
std::string PolicyParamToTestSuffix(
const ::testing::TestParamInfo<PolicyTestParam>& info) {
return info.param.key + "_" + info.param.value;
}
class FirstRunServicePolicyBrowserTest
: public FirstRunServiceBrowserTest,
public testing::WithParamInterface<PolicyTestParam> {
public:
void SetUpInProcessBrowserTestFixture() override {
FirstRunServiceBrowserTest::SetUpInProcessBrowserTestFixture();
policy_provider_.SetDefaultReturns(
/*is_initialization_complete_return=*/true,
/*is_first_policy_load_complete_return=*/true);
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
&policy_provider_);
}
void SetPolicy(const std::string& key, const std::string& value) {
auto* policy_service = g_browser_process->policy_service();
ASSERT_TRUE(policy_service);
policy::PolicyMap policy;
policy.Set(key, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_PLATFORM, GetJSONAsValue(value), nullptr);
base::RunLoop run_loop;
PolicyUpdateObserver policy_update_observer{*policy_service,
run_loop.QuitClosure()};
policy_provider_.UpdateChromePolicy(policy);
run_loop.Run();
}
private:
base::test::ScopedFeatureList scoped_feature_list_{kForYouFre};
testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
};
IN_PROC_BROWSER_TEST_P(FirstRunServicePolicyBrowserTest, OpenFirstRunIfNeeded) {
base::HistogramTester histogram_tester;
signin_util::ResetForceSigninForTesting();
SetPolicy(GetParam().key, GetParam().value);
// The attempt to run the FRE should not be blocked
EXPECT_TRUE(ShouldOpenFirstRun(browser()->profile()));
EXPECT_TRUE(IsProfileNameDefault());
// However the FRE should be silently marked as finished due to policies
// forcing to skip it.
ASSERT_TRUE(fre_service());
base::RunLoop run_loop;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// On Lacros the silent finish happens right when the service is created.
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
// Quitting the loop for consistency with the dice code path. Posting the task
// is important to get the profile name resolution's timeout task to run
// before the assertions below.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, run_loop.QuitClosure());
#else
fre_service()->OpenFirstRunIfNeeded(
FirstRunService::EntryPoint::kOther,
base::IgnoreArgs<bool>(run_loop.QuitClosure()));
EXPECT_EQ(GetParam().should_open_fre, ProfilePicker::IsOpen());
#endif
EXPECT_NE(GetParam().should_open_fre, GetFirstRunFinishedPrefValue());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
if (GetParam().should_open_fre) {
histogram_tester.ExpectTotalCount(
"Profile.LacrosPrimaryProfileFirstRunOutcome", 0);
} else {
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
ProfilePicker::Hide();
run_loop.Run();
absl::optional<std::u16string> expected_profile_name;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// On Lacros we always have an account, the profile name will reflect it.
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
CoreAccountInfo account_info =
identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
expected_profile_name = base::ASCIIToUTF16(account_info.email);
#else
// On Dice platforms, we use a default enterprise name after skipped FREs.
if (!GetParam().should_open_fre) {
expected_profile_name = l10n_util::GetStringUTF16(
IDS_SIGNIN_DICE_WEB_INTERCEPT_ENTERPRISE_PROFILE_NAME);
}
#endif
if (expected_profile_name.has_value()) {
EXPECT_EQ(*expected_profile_name, GetProfileName());
} else {
EXPECT_TRUE(IsProfileNameDefault());
}
}
INSTANTIATE_TEST_SUITE_P(,
FirstRunServicePolicyBrowserTest,
testing::ValuesIn(kPolicyTestParams),
&PolicyParamToTestSuffix);
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
struct FeatureTestParams {
const base::FieldTrialParams feature_params;
const bool expected_proceed;
};
const FeatureTestParams kFeatureTestParams[] = {
{.feature_params = {{"close_should_proceed", "false"}},
.expected_proceed = false},
{.feature_params = {{"close_should_proceed", "true"}},
.expected_proceed = true},
};
std::string FeatureParamToTestSuffix(
const ::testing::TestParamInfo<FeatureTestParams>& info) {
std::vector<std::string> pieces;
for (const auto& feature_param : info.param.feature_params) {
pieces.push_back(feature_param.first);
pieces.push_back(feature_param.second);
}
return base::JoinString(pieces, "_");
}
class FirstRunServiceFeatureParamsBrowserTest
: public FirstRunServiceBrowserTest,
public testing::WithParamInterface<FeatureTestParams> {
public:
FirstRunServiceFeatureParamsBrowserTest() {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
kForYouFre, GetParam().feature_params);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(FirstRunServiceFeatureParamsBrowserTest, CloseProceeds) {
base::HistogramTester histogram_tester;
base::test::TestFuture<bool> proceed_future;
ASSERT_TRUE(fre_service());
EXPECT_TRUE(fre_service()->ShouldOpenFirstRun());
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
proceed_future.GetCallback());
profiles::testing::WaitForPickerWidgetCreated();
EXPECT_FALSE(GetFirstRunFinishedPrefValue());
ProfilePicker::Hide();
EXPECT_EQ(GetParam().expected_proceed, proceed_future.Get());
EXPECT_TRUE(GetFirstRunFinishedPrefValue());
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
// We log `QuitAtEnd`, whether proceed is overridden or not.
histogram_tester.ExpectUniqueSample(
"ProfilePicker.FirstRun.ExitStatus",
ProfilePicker::FirstRunExitStatus::kQuitAtEnd, 1);
}
INSTANTIATE_TEST_SUITE_P(,
FirstRunServiceFeatureParamsBrowserTest,
testing::ValuesIn(kFeatureTestParams),
&FeatureParamToTestSuffix);
#endif