blob: 2abd558b34830522763f7dcac9bca428bcf25af3 [file] [log] [blame]
// Copyright 2018 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/ash/login/demo_mode/demo_session.h"
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/timer/mock_timer.h"
#include "chrome/browser/ash/login/demo_mode/demo_components.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/wallpaper_handlers/test_wallpaper_fetcher_delegate.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/ui/ash/wallpaper/test_wallpaper_controller.h"
#include "chrome/browser/ui/ash/wallpaper/wallpaper_controller_client_impl.h"
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "components/component_updater/ash/fake_component_manager_ash.h"
#include "components/language/core/browser/pref_names.h"
#include "components/session_manager/core/session_manager.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/common/extension_builder.h"
#include "google_apis/gaia/gaia_id.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
using ::component_updater::FakeComponentManagerAsh;
constexpr char kResourcesComponent[] = "demo-mode-resources";
constexpr char kTestDemoModeResourcesMountPoint[] =
"/run/imageloader/demo_mode_resources";
class DemoSessionTest : public testing::Test {
public:
DemoSessionTest()
: fake_user_manager_(std::make_unique<ash::FakeChromeUserManager>()),
profile_manager_(std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal())),
browser_process_platform_part_test_api_(
g_browser_process->platform_part()) {
cros_settings_test_helper_.InstallAttributes()->SetDemoMode();
}
DemoSessionTest(const DemoSessionTest&) = delete;
DemoSessionTest& operator=(const DemoSessionTest&) = delete;
~DemoSessionTest() override = default;
void SetUp() override {
ASSERT_TRUE(profile_manager_->SetUp());
ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);
DemoSession::SetDemoConfigForTesting(DemoSession::DemoModeConfig::kOnline);
InitializeComponentManager();
session_manager_ = std::make_unique<session_manager::SessionManager>();
wallpaper_controller_client_ = std::make_unique<
WallpaperControllerClientImpl>(
std::make_unique<wallpaper_handlers::TestWallpaperFetcherDelegate>());
wallpaper_controller_client_->InitForTesting(&test_wallpaper_controller_);
// TODO(b/321321392): Test loading growth campaigns at session start.
scoped_feature_list_.InitAndDisableFeature(
ash::features::kGrowthCampaignsInDemoMode);
}
void TearDown() override {
DemoSession::ShutDownIfInitialized();
DemoSession::ResetDemoConfigForTesting();
wallpaper_controller_client_.reset();
ConciergeClient::Shutdown();
component_manager_ash_ = nullptr;
browser_process_platform_part_test_api_.ShutdownComponentManager();
profile_manager_->DeleteAllTestingProfiles();
}
protected:
bool FinishResourcesComponentLoad(const base::FilePath& mount_path) {
EXPECT_TRUE(component_manager_ash_->HasPendingInstall(kResourcesComponent));
EXPECT_TRUE(component_manager_ash_->UpdateRequested(kResourcesComponent));
return component_manager_ash_->FinishLoadRequest(
kResourcesComponent,
FakeComponentManagerAsh::ComponentInfo(
component_updater::ComponentManagerAsh::Error::NONE,
base::FilePath("/dev/null"), mount_path));
}
void InitializeComponentManager() {
auto fake_component_manager_ash =
base::MakeRefCounted<FakeComponentManagerAsh>();
fake_component_manager_ash->set_queue_load_requests(true);
fake_component_manager_ash->set_supported_components({kResourcesComponent});
component_manager_ash_ = fake_component_manager_ash.get();
browser_process_platform_part_test_api_.InitializeComponentManager(
std::move(fake_component_manager_ash));
}
// Creates a dummy demo user with a testing profile and logs in.
TestingProfile* LoginDemoUser() {
const AccountId account_id(
AccountId::FromUserEmailGaiaId("demo@test.com", GaiaId("demo_user")));
fake_user_manager_->AddPublicAccountUser(account_id);
auto prefs =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
RegisterUserProfilePrefs(prefs->registry());
TestingProfile* profile = profile_manager_->CreateTestingProfile(
account_id.GetUserEmail(), std::move(prefs), u"Test profile",
/*avatar_id=*/1, TestingProfile::TestingFactories());
fake_user_manager_->LoginUser(account_id);
return profile;
}
raw_ptr<FakeComponentManagerAsh> component_manager_ash_ = nullptr;
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<session_manager::SessionManager> session_manager_;
std::unique_ptr<WallpaperControllerClientImpl> wallpaper_controller_client_;
TestWallpaperController test_wallpaper_controller_;
user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
fake_user_manager_;
std::unique_ptr<TestingProfileManager> profile_manager_;
ScopedCrosSettingsTestHelper cros_settings_test_helper_;
base::UserActionTester user_action_tester_;
private:
BrowserProcessPlatformPartTestApi browser_process_platform_part_test_api_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(DemoSessionTest, StartForDeviceInDemoMode) {
EXPECT_FALSE(DemoSession::Get());
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
EXPECT_TRUE(demo_session->started());
EXPECT_EQ(demo_session, DemoSession::Get());
}
TEST_F(DemoSessionTest, StartForDemoDeviceNotInDemoMode) {
cros_settings_test_helper_.InstallAttributes()->SetConsumerOwned();
EXPECT_FALSE(DemoSession::Get());
EXPECT_FALSE(DemoSession::StartIfInDemoMode());
EXPECT_FALSE(DemoSession::Get());
EXPECT_FALSE(component_manager_ash_->HasPendingInstall(kResourcesComponent));
}
TEST_F(DemoSessionTest, ShutdownResetsInstance) {
ASSERT_TRUE(DemoSession::StartIfInDemoMode());
EXPECT_TRUE(DemoSession::Get());
DemoSession::ShutDownIfInitialized();
EXPECT_FALSE(DemoSession::Get());
}
TEST_F(DemoSessionTest, LoginDemoSession) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
// There should be no user action DemoMode.DemoSessionStarts reported
// before the user login
EXPECT_EQ(0,
user_action_tester_.GetActionCount("DemoMode.DemoSessionStarts"));
LoginDemoUser();
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
EXPECT_EQ(1,
user_action_tester_.GetActionCount("DemoMode.DemoSessionStarts"));
}
TEST_F(DemoSessionTest, ShowAndRemoveSplashScreen) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
std::unique_ptr<base::MockOneShotTimer> timer =
std::make_unique<base::MockOneShotTimer>();
demo_session->SetTimerForTesting(std::move(timer));
EXPECT_EQ(0, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
session_manager_->SetSessionState(
session_manager::SessionState::LOGIN_PRIMARY);
EXPECT_EQ(0, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
ASSERT_TRUE(FinishResourcesComponentLoad(
base::FilePath(kTestDemoModeResourcesMountPoint)));
// Wait for splash screen image to load and timer to be set
task_environment_.RunUntilIdle();
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
// The splash screen is not removed upon the active session starts.
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
// Explicitly remove the splash screen as if the fullscreen is toggled.
demo_session->RemoveSplashScreen();
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(1, test_wallpaper_controller_.remove_override_wallpaper_count());
// The timer is cleared after splash screen is removed.
EXPECT_FALSE(demo_session->GetTimerForTesting());
// Explicitly remove the splash screen again as if the fullscreen is
// toggled again. But it should have no effect since the splash screen
// is already removed.
demo_session->RemoveSplashScreen();
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(1, test_wallpaper_controller_.remove_override_wallpaper_count());
}
TEST_F(DemoSessionTest, RemoveSplashScreenWhenTimeout) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
std::unique_ptr<base::MockOneShotTimer> timer =
std::make_unique<base::MockOneShotTimer>();
demo_session->SetTimerForTesting(std::move(timer));
EXPECT_EQ(0, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
session_manager_->SetSessionState(
session_manager::SessionState::LOGIN_PRIMARY);
EXPECT_EQ(0, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
ASSERT_TRUE(FinishResourcesComponentLoad(
base::FilePath(kTestDemoModeResourcesMountPoint)));
// Wait for splash screen image to load and timer to be set
task_environment_.RunUntilIdle();
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(0, test_wallpaper_controller_.remove_override_wallpaper_count());
base::MockOneShotTimer* timer_ptr =
static_cast<base::MockOneShotTimer*>(demo_session->GetTimerForTesting());
ASSERT_TRUE(timer_ptr);
timer_ptr->Fire();
// The splash screen should be removed when the timer goes off.
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(1, test_wallpaper_controller_.remove_override_wallpaper_count());
// Explicitly remove the splash screen again as if the fullscreen is
// toggled. But it should have no effect since the splash screen is already
// removed.
demo_session->RemoveSplashScreen();
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(1, test_wallpaper_controller_.remove_override_wallpaper_count());
// Entering active session will not trigger splash screen removal anymore.
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count());
EXPECT_EQ(1, test_wallpaper_controller_.show_override_wallpaper_count(
/*always_on_top=*/true));
EXPECT_EQ(1, test_wallpaper_controller_.remove_override_wallpaper_count());
}
using DemoSessionLocaleTest = DemoSessionTest;
TEST_F(DemoSessionLocaleTest, InitializeDefaultLocale) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
TestingProfile* profile = LoginDemoUser();
// When the default locale is empty, verify that it's initialized with the
// current locale.
constexpr char kCurrentLocale[] = "en-US";
profile->GetPrefs()->SetString(language::prefs::kApplicationLocale,
kCurrentLocale);
EXPECT_EQ("", TestingBrowserProcess::GetGlobal()->local_state()->GetString(
prefs::kDemoModeDefaultLocale));
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
EXPECT_EQ(kCurrentLocale,
TestingBrowserProcess::GetGlobal()->local_state()->GetString(
prefs::kDemoModeDefaultLocale));
EXPECT_FALSE(profile->requested_locale().has_value());
}
TEST_F(DemoSessionLocaleTest, DefaultAndCurrentLocaleDifferent) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
TestingProfile* profile = LoginDemoUser();
// When the default locale is different from the current locale, verify that
// reverting to default locale is requested.
constexpr char kCurrentLocale[] = "zh-CN";
constexpr char kDefaultLocale[] = "en-US";
profile->GetPrefs()->SetString(language::prefs::kApplicationLocale,
kCurrentLocale);
TestingBrowserProcess::GetGlobal()->local_state()->SetString(
prefs::kDemoModeDefaultLocale, kDefaultLocale);
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
EXPECT_EQ(kDefaultLocale,
TestingBrowserProcess::GetGlobal()->local_state()->GetString(
prefs::kDemoModeDefaultLocale));
EXPECT_EQ(kDefaultLocale, profile->requested_locale().value());
}
TEST_F(DemoSessionLocaleTest, DefaultAndCurrentLocaleIdentical) {
DemoSession* demo_session = DemoSession::StartIfInDemoMode();
ASSERT_TRUE(demo_session);
TestingProfile* profile = LoginDemoUser();
// When the default locale is the same with the current locale, verify that
// it's no-op.
constexpr char kDefaultLocale[] = "en-US";
profile->GetPrefs()->SetString(language::prefs::kApplicationLocale,
kDefaultLocale);
TestingBrowserProcess::GetGlobal()->local_state()->SetString(
prefs::kDemoModeDefaultLocale, kDefaultLocale);
session_manager_->SetSessionState(session_manager::SessionState::ACTIVE);
EXPECT_EQ(kDefaultLocale,
TestingBrowserProcess::GetGlobal()->local_state()->GetString(
prefs::kDemoModeDefaultLocale));
EXPECT_FALSE(profile->requested_locale().has_value());
}
} // namespace
} // namespace ash