blob: 9006c3a941142e60bebe24c0c50eedf83d514d68 [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/callback_forward.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/browser_process.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/ui/browser.h"
#include "chrome/browser/ui/profile_picker.h"
#include "chrome/browser/ui/profile_ui_test_utils.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_info.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 "content/public/test/browser_test.h"
#include "google_apis/gaia/core_account_id.h"
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/lacros/device_settings_lacros.h"
#include "chrome/browser/lacros/lacros_prefs.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/device_settings_service.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
#endif
class FirstRunServiceBrowserTest : public InProcessBrowserTest {
public:
void SetUpOnMainThread() override {
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
browser()->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();
}
FirstRunService* fre_service() {
Profile* profile = browser()->profile();
return FirstRunServiceFactory::GetForBrowserContext(profile);
}
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_;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Only Dice guards the FRE behind a feature flag.
base::test::ScopedFeatureList scoped_feature_list_{kForYouFre};
#endif
};
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
TryMarkFirstRunAlreadyFinished_DoesNothing) {
// Setup note: We are removing `switches::kNoFirstRun` only after the browser
// is opened to simplify the setup. This allows us to call FRE-related methods
// without having to do more elaborate things to avoid it triggering before
// the test starts.
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
EXPECT_TRUE(fre_service()->ShouldOpenFirstRun());
base::HistogramTester histogram_tester;
base::RunLoop run_loop;
fre_service()->TryMarkFirstRunAlreadyFinished(run_loop.QuitClosure());
run_loop.Run();
EXPECT_FALSE(
g_browser_process->local_state()->GetBoolean(prefs::kFirstRunFinished));
EXPECT_TRUE(fre_service()->ShouldOpenFirstRun());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
histogram_tester.ExpectTotalCount(
"Profile.LacrosPrimaryProfileFirstRunOutcome", 0);
#endif
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
TryMarkFirstRunAlreadyFinished_SucceedsAlreadySyncing) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
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;
base::RunLoop run_loop;
fre_service()->TryMarkFirstRunAlreadyFinished(run_loop.QuitClosure());
// Future attempts are synchronously disabled.
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
run_loop.Run();
EXPECT_TRUE(
g_browser_process->local_state()->GetBoolean(prefs::kFirstRunFinished));
EXPECT_FALSE(fre_service()->ShouldOpenFirstRun());
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedAlreadySyncing, 1);
}
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest,
TryMarkFirstRunAlreadyFinished_SyncConsentDisabled) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
Profile* profile = browser()->profile();
signin::IdentityManager* identity_manager =
identity_test_env()->identity_manager();
base::HistogramTester histogram_tester;
profile->GetPrefs()->SetBoolean(prefs::kEnableSyncConsent, false);
base::RunLoop run_loop;
fre_service()->TryMarkFirstRunAlreadyFinished(run_loop.QuitClosure());
EXPECT_FALSE(ShouldOpenFirstRun(profile));
run_loop.Run();
EXPECT_TRUE(
g_browser_process->local_state()->GetBoolean(prefs::kFirstRunFinished));
EXPECT_FALSE(ShouldOpenFirstRun(profile));
EXPECT_TRUE(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
IN_PROC_BROWSER_TEST_F(
FirstRunServiceBrowserTest,
TryMarkFirstRunAlreadyFinished_DeviceEphemeralUsersEnabled) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
Profile* profile = browser()->profile();
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->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));
base::RunLoop run_loop;
fre_service()->TryMarkFirstRunAlreadyFinished(run_loop.QuitClosure());
EXPECT_FALSE(ShouldOpenFirstRun(profile));
run_loop.Run();
EXPECT_TRUE(
g_browser_process->local_state()->GetBoolean(prefs::kFirstRunFinished));
EXPECT_FALSE(ShouldOpenFirstRun(profile));
EXPECT_TRUE(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
histogram_tester.ExpectUniqueSample(
"Profile.LacrosPrimaryProfileFirstRunOutcome",
ProfileMetrics::ProfileSignedInFlowOutcome::kSkippedByPolicies, 1);
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest, ShouldOpenFirstRun) {
EXPECT_FALSE(ShouldOpenFirstRun(browser()->profile()));
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
EXPECT_TRUE(ShouldOpenFirstRun(browser()->profile()));
g_browser_process->local_state()->SetBoolean(prefs::kFirstRunFinished, true);
EXPECT_FALSE(ShouldOpenFirstRun(browser()->profile()));
}
#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,
ShouldOpenFirstRun_NeverOnDice) {
EXPECT_FALSE(ShouldOpenFirstRun(browser()->profile()));
EXPECT_EQ(nullptr, fre_service());
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
EXPECT_FALSE(ShouldOpenFirstRun(browser()->profile()));
}
#endif
IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest, OpenFirstRunIfNeeded) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(switches::kNoFirstRun);
fre_service()->OpenFirstRunIfNeeded(FirstRunService::EntryPoint::kOther,
base::DoNothing());
profiles::testing::WaitForPickerWidgetCreated();
// TODO(crbug.com/1375277): Check that the callback is run on closure.
// TODO(crbug.com/1375277): Check the logic that makes the FRE run only once.
EXPECT_TRUE(ShouldOpenFirstRun(browser()->profile()));
}