blob: d8ec63b7136424fb542371e69533f7a7b8604f32 [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 <memory>
#include <optional>
#include <string_view>
#include "ash/components/arc/session/arc_service_manager.h"
#include "ash/components/arc/session/arc_session_runner.h"
#include "ash/components/arc/test/arc_util_test_support.h"
#include "ash/components/arc/test/fake_arc_session.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/login_screen_test_api.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "build/branding_buildflags.h"
#include "build/buildflag.h"
#include "chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher.h"
#include "chrome/browser/apps/app_discovery_service/recommended_arc_apps/recommend_apps_fetcher_delegate.h"
#include "chrome/browser/apps/app_discovery_service/recommended_arc_apps/scoped_test_recommend_apps_fetcher_factory.h"
#include "chrome/browser/ash/arc/session/arc_service_launcher.h"
#include "chrome/browser/ash/arc/session/arc_session_manager.h"
#include "chrome/browser/ash/arc/test/test_arc_session_manager.h"
#include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/embedded_test_server_setup_mixin.h"
#include "chrome/browser/ash/login/test/enrollment_ui_mixin.h"
#include "chrome/browser/ash/login/test/fake_arc_tos_mixin.h"
#include "chrome/browser/ash/login/test/fake_eula_mixin.h"
#include "chrome/browser/ash/login/test/js_checker.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/login/test/login_or_lock_screen_visible_waiter.h"
#include "chrome/browser/ash/login/test/oobe_base_test.h"
#include "chrome/browser/ash/login/test/oobe_screen_exit_waiter.h"
#include "chrome/browser/ash/login/test/oobe_screen_waiter.h"
#include "chrome/browser/ash/login/test/oobe_screens_utils.h"
#include "chrome/browser/ash/login/test/scoped_policy_update.h"
#include "chrome/browser/ash/login/test/test_predicate_waiter.h"
#include "chrome/browser/ash/login/wizard_controller.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_controller.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.h"
#include "chrome/browser/ash/policy/enrollment/psm/rlwe_test_support.h"
#include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h"
#include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/login/login_display_host.h"
#include "chrome/browser/ui/webui/ash/login/ai_intro_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/app_downloading_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/assistant_optin_flow_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/choobe_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/consumer_update_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/display_size_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/gaia_info_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/gemini_intro_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/gesture_navigation_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/marketing_opt_in_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/password_selection_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/recommend_apps_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/sync_consent_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/terms_of_service_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/theme_selection_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/touchpad_scroll_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/tpm_error_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/user_creation_screen_handler.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/fake_gaia_mixin.h"
#include "chromeos/ash/components/assistant/buildflags.h"
#include "chromeos/ash/components/attestation/stub_attestation_features.h"
#include "chromeos/ash/components/dbus/attestation/attestation_client.h"
#include "chromeos/ash/components/dbus/constants/attestation_constants.h"
#include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
#include "chromeos/ash/components/system/fake_statistics_provider.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "components/policy/core/common/policy_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/display/display_switches.h"
namespace ash {
namespace {
using ::net::test_server::BasicHttpResponse;
using ::net::test_server::HttpRequest;
using ::net::test_server::HttpResponse;
enum class ArcState { kNotAvailable, kAcceptTerms };
std::string ArcStateToString(ArcState arc_state) {
switch (arc_state) {
case ArcState::kNotAvailable:
return "not-available";
case ArcState::kAcceptTerms:
return "accept-terms";
}
}
void RunWelcomeScreenChecks() {
test::OobeJS()
.CreateFocusWaiter({"connect", "welcomeScreen", "getStarted"})
->Wait();
test::OobeJS().ExpectVisiblePath({"connect", "welcomeScreen"});
test::OobeJS().ExpectHiddenPath({"connect", "accessibilityScreen"});
test::OobeJS().ExpectHiddenPath({"connect", "languageScreen"});
test::OobeJS().ExpectHiddenPath({"connect", "timezoneScreen"});
test::OobeJS().ExpectFocused({"connect", "welcomeScreen", "getStarted"});
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
EXPECT_TRUE(test::IsScanningRequestedOnNetworkScreen());
}
void RunNetworkSelectionScreenChecks() {
test::OobeJS().ExpectEnabledPath({"network-selection", "nextButton"});
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
test::OobeJS().CreateFocusWaiter({"network-selection", "nextButton"})->Wait();
EXPECT_TRUE(test::IsScanningRequestedOnNetworkScreen());
}
void HandleGaiaInfoScreen() {
OobeScreenWaiter(GaiaInfoScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'gaia-info' screen.";
test::OobeJS().ClickOnPath({"gaia-info", "nextButton"});
LOG(INFO) << "OobeInteractiveUITest: Exiting 'gaia-info' screen.";
}
void HandleConsumerUpdateScreen() {
OobeScreenWaiter(ConsumerUpdateScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'consumer-update' screen.";
test::ExitConsumerUpdateScreenNoUpdate();
}
void WaitForGaiaSignInScreen() {
OobeScreenWaiter(GaiaView::kScreenId).Wait();
test::OobeJS()
.CreateVisibilityWaiter(true, {"gaia-signin", "signin-frame-dialog"})
->Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'gaia-signin' screen.";
}
void LogInAsRegularUser() {
LoginDisplayHost::default_host()
->GetOobeUI()
->GetView<GaiaScreenHandler>()
->ShowSigninScreenForTest(FakeGaiaMixin::kFakeUserEmail,
FakeGaiaMixin::kFakeUserPassword,
FakeGaiaMixin::kEmptyUserServices);
LOG(INFO) << "OobeInteractiveUITest: Logged in.";
}
void RunConsolidatedConsentScreenChecks() {
test::OobeJS()
.CreateVisibilityWaiter(true, {"consolidated-consent", "loadedDialog"})
->Wait();
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
}
void RunSyncConsentScreenChecks() {
SyncConsentScreen* screen = static_cast<SyncConsentScreen*>(
WizardController::default_controller()->GetScreen(
SyncConsentScreenView::kScreenId));
screen->SetProfileSyncEngineInitializedForTesting(true);
screen->OnStateChanged(nullptr);
const std::string button_name = "acceptButton";
test::OobeJS().ExpectEnabledPath({"sync-consent", button_name});
test::OobeJS().CreateFocusWaiter({"sync-consent", button_name})->Wait();
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
}
void RunFingerprintScreenChecks() {
test::OobeJS().ExpectVisible("fingerprint-setup");
test::OobeJS().ExpectVisiblePath({"fingerprint-setup", "setupFingerprint"});
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
}
void RunPinSetupScreenChecks() {
test::OobeJS().ExpectVisible("pin-setup");
test::OobeJS().ExpectVisiblePath({"pin-setup", "setup"});
test::OobeJS().CreateFocusWaiter({"pin-setup", "pinKeyboard"})->Wait();
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
}
// Waits for the recommend apps screen to be shown, selects the single app
// reported by FakeRecommendAppsFetcher, and requests the apps install. It
// will wait for the flow to progress away from the RecommendAppsScreen before
// returning.
void HandleRecommendAppsScreen() {
OobeScreenWaiter(RecommendAppsScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'recommend-apps' screen.";
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
test::OobeJS()
.CreateVisibilityWaiter(true, {"recommend-apps", "appsDialog"})
->Wait();
test::OobeJS().ClickOnPath(
{"recommend-apps", "appsList", R"(test\\.package)"});
const std::initializer_list<std::string_view> install_button = {
"recommend-apps", "installButton"};
test::OobeJS().CreateEnabledWaiter(true, install_button)->Wait();
test::OobeJS().TapOnPath(install_button);
OobeScreenExitWaiter(RecommendAppsScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'recommend-apps' screen done.";
}
// Waits for PasswordSelectionScreen to be shown, selects 'Gaia password' option
// and clicks next to go to the next screen.
void HandlePasswordSelectionScreen() {
OobeScreenWaiter(PasswordSelectionScreenView::kScreenId).Wait();
LOG(INFO)
<< "OobeInteractiveUITest: Switched to 'password-selection' screen.";
test::OobeJS().CreateVisibilityWaiter(true, {"password-selection"})->Wait();
test::OobeJS().ClickOnPath({"password-selection", "gaiaPasswordButton"});
test::OobeJS().ExpectVisiblePath({"password-selection", "nextButton"});
test::OobeJS().ExecuteAsync("$('password-selection').$.nextButton.click()");
OobeScreenExitWaiter(PasswordSelectionScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'password-selection' screen done.";
}
// Waits for AppDownloadingScreen to be shown, clicks 'Continue' button, and
// waits until the flow moves to the next screen. This assumes that an app was
// selected in HandleRecommendAppsScreen.
void HandleAppDownloadingScreen() {
OobeScreenWaiter(AppDownloadingScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'app-downloading' screen.";
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
const std::initializer_list<std::string_view> continue_button = {
"app-downloading", "continue-setup-button"};
test::OobeJS().TapOnPath(continue_button);
OobeScreenExitWaiter(AppDownloadingScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'app-downloading' screen done.";
}
// Waits for AiIntroScreen to be shown and clicks next to go to the next screen.
void HandleAiIntroScreen() {
OobeScreenWaiter(AiIntroScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'ai-intro' screen.";
test::OobeJS().TapOnPathAsync({"ai-intro", "nextButton"});
OobeScreenExitWaiter(AiIntroScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'ai-intro' screen done.";
}
// Waits for GeminiIntroScreen to be shown and clicks next to go to the next
// screen.
void HandleGeminiIntroScreen() {
OobeScreenWaiter(GeminiIntroScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'gemini-intro' screen.";
test::OobeJS().TapOnPathAsync({"gemini-intro", "nextButton"});
OobeScreenExitWaiter(GeminiIntroScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'gemini-intro' screen done.";
}
// Waits for AssistantOptInFlowScreen to be shown, skips the opt-in, and waits
// for the flow to move away from the screen.
// Note that due to test setup, the screen will fail to load assistant value
// proposal error (as the URL is not faked in this test), and display an
// error, This is good enough for this tests, whose goal is to verify the
// screen is shown, and how the setup progresses after the screen. The actual
// assistant opt-in flow is tested separately.
void HandleAssistantOptInScreen() {
#if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
OobeScreenWaiter(AssistantOptInFlowScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: Switched to 'assistant-optin' screen.";
EXPECT_FALSE(LoginScreenTestApi::IsShutdownButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown());
EXPECT_FALSE(LoginScreenTestApi::IsAddUserButtonShown());
test::OobeJS()
.CreateVisibilityWaiter(true, {"assistant-optin-flow", "card", "loading"})
->Wait();
std::initializer_list<std::string_view> skip_button_path = {
"assistant-optin-flow", "card", "loading", "skip-button"};
test::OobeJS().CreateEnabledWaiter(true, skip_button_path)->Wait();
test::OobeJS().TapOnPath(skip_button_path);
OobeScreenExitWaiter(AssistantOptInFlowScreenView::kScreenId).Wait();
LOG(INFO) << "OobeInteractiveUITest: 'assistant-optin' screen done.";
#endif
}
// Waits for gesture navigation to get shown, runs through all pages in the
// screen, and waits for the screen to exit.
void HandleGestureNavigationScreen() {
OobeScreenWaiter(GestureNavigationScreenView::kScreenId).Wait();
struct {
std::string page_id;
std::string button_id;
} kPages[] = {{"gestureIntro", "gesture-intro-next-button"},
{"gestureHome", "gesture-home-next-button"},
{"gestureOverview", "gesture-overview-next-button"},
{"gestureBack", "gesture-back-next-button"}};
for (const auto& page : kPages) {
SCOPED_TRACE(page.page_id);
test::OobeJS()
.CreateVisibilityWaiter(true, {"gesture-navigation", page.page_id})
->Wait();
test::OobeJS().TapOnPath({"gesture-navigation", page.button_id});
}
OobeScreenExitWaiter(GestureNavigationScreenView::kScreenId).Wait();
}
// Waits for theme selection to get shown, then taps through the screen
// and waits for the screen to exit.
void HandleThemeSelectionScreen() {
OobeScreenWaiter(ThemeSelectionScreenView::kScreenId).Wait();
// Enable the tablet mode shelf navigation buttons so that the next button
// is shown on the marketing opt in screen in tablet mode.
ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityTabletModeShelfNavigationButtonsEnabled, true);
test::OobeJS().CreateVisibilityWaiter(true, {"theme-selection"})->Wait();
test::OobeJS()
.CreateVisibilityWaiter(true, {"theme-selection", "nextButton"})
->Wait();
test::OobeJS().TapOnPath({"theme-selection", "nextButton"});
OobeScreenExitWaiter(ThemeSelectionScreenView::kScreenId).Wait();
}
// Waits for display size screen to get shown, then taps through the screen
// and waits for the screen to exit.
void HandleDisplaySizeScreen() {
OobeScreenWaiter(DisplaySizeScreenView::kScreenId).Wait();
test::OobeJS().ClickOnPath({"display-size", "nextButton"});
OobeScreenExitWaiter(DisplaySizeScreenView::kScreenId).Wait();
}
// Waits for touchpad scroll screen to get shown, then taps through the screen
// and waits for the screen to exit.
void HandleTouchpadScrollScreen() {
OobeScreenWaiter(TouchpadScrollScreenView::kScreenId).Wait();
test::OobeJS().ClickOnPath({"touchpad-scroll", "nextButton"});
OobeScreenExitWaiter(TouchpadScrollScreenView::kScreenId).Wait();
}
// Waits for CHOOBE screen to get shown, selects all screens cards, then taps
// through the screen and waits for the screen to exit.
void HandleChoobeScreen() {
OobeScreenWaiter(ChoobeScreenView::kScreenId).Wait();
const test::UIPath screens_cards[] = {
{"choobe", "screensList", "cr-button-touchpad-scroll"},
{"choobe", "screensList", "cr-button-display-size"},
{"choobe", "screensList", "cr-button-theme-selection"}};
for (const auto& card : screens_cards) {
test::OobeJS().TapOnPath(card);
}
test::OobeJS().TapOnPath({"choobe", "nextButton"});
OobeScreenExitWaiter(ChoobeScreenView::kScreenId).Wait();
}
// Taps through CHOOBE screen (if it should be shown), then calls the handle
// methods for the optional sreens.
void HandleChoobeFlow() {
// CHOOBE screen will only be enabled when there are at least 3 eligible
// optional screens. So, for the screen to be shown, both `OobeDisplaySize`
// and `OobeTouchpadScroll` must be enabled to have at least 3 optional
// screens.
bool should_show_choobe = features::IsOobeDisplaySizeEnabled() &&
features::IsOobeTouchpadScrollEnabled();
if (should_show_choobe) {
HandleChoobeScreen();
}
if (features::IsOobeTouchpadScrollEnabled()) {
HandleTouchpadScrollScreen();
}
if (features::IsOobeDisplaySizeEnabled()) {
HandleDisplaySizeScreen();
}
HandleThemeSelectionScreen();
}
// Waits for marketing opt in screen to get shown, then taps through the screen
// and waits for the screen to exit.
void HandleMarketingOptInScreen() {
OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
// Enable the tablet mode shelf navigation buttons so that the next button
// is shown on the marketing opt in screen in tablet mode.
ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityTabletModeShelfNavigationButtonsEnabled, true);
test::OobeJS().CreateVisibilityWaiter(true, {"marketing-opt-in"})->Wait();
test::OobeJS()
.CreateVisibilityWaiter(
true, {"marketing-opt-in", "marketing-opt-in-next-button"})
->Wait();
test::OobeJS()
.CreateFocusWaiter({"marketing-opt-in", "marketing-opt-in-next-button"})
->Wait();
test::OobeJS().TapOnPath(
{"marketing-opt-in", "marketing-opt-in-next-button"});
OobeScreenExitWaiter(MarketingOptInScreenView::kScreenId).Wait();
}
class FakeRecommendAppsFetcher : public apps::RecommendAppsFetcher {
public:
explicit FakeRecommendAppsFetcher(
apps::RecommendAppsFetcherDelegate* delegate)
: delegate_(delegate) {}
~FakeRecommendAppsFetcher() override = default;
// RecommendAppsFetcher:
void Start() override {
base::Value::Dict app;
app.Set("packageName", "test.package");
app.Set("title", "TestName");
base::Value::Dict big_app;
big_app.Set("androidApp", std::move(app));
base::Value::List app_list;
app_list.Append(std::move(big_app));
base::Value::Dict response_dict;
response_dict.Set("recommendedApp", std::move(app_list));
delegate_->OnLoadSuccess(base::Value(std::move(response_dict)));
}
void Retry() override { NOTREACHED(); }
private:
const raw_ptr<apps::RecommendAppsFetcherDelegate> delegate_;
};
std::unique_ptr<apps::RecommendAppsFetcher> CreateRecommendAppsFetcher(
apps::RecommendAppsFetcherDelegate* delegate) {
return std::make_unique<FakeRecommendAppsFetcher>(delegate);
}
// Observes an `aura::Window` to see if the window was visible at some point in
// time.
class NativeWindowVisibilityObserver : public aura::WindowObserver {
public:
NativeWindowVisibilityObserver() = default;
NativeWindowVisibilityObserver(const NativeWindowVisibilityObserver&) =
delete;
NativeWindowVisibilityObserver& operator=(
const NativeWindowVisibilityObserver&) = delete;
// aura::Window will remove observers on destruction.
~NativeWindowVisibilityObserver() override = default;
void Observe(aura::Window* window) {
window_ = window;
window_->AddObserver(this);
}
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
if (visible) {
was_visible_ = visible;
}
}
bool was_visible() { return was_visible_; }
private:
// The window was visible at some point in time.
bool was_visible_ = false;
raw_ptr<aura::Window> window_;
};
// Sets the `NativeWindowVisibilityObserver` to observe the
// `LoginDisplayHost`'s `NativeWindow`. This needs to be done in
// `PostProfileInit()` as the `default_host` will not be initialized before
// this.
class NativeWindowVisibilityBrowserMainExtraParts
: public ChromeBrowserMainExtraParts {
public:
explicit NativeWindowVisibilityBrowserMainExtraParts(
NativeWindowVisibilityObserver* observer)
: observer_(observer) {}
NativeWindowVisibilityBrowserMainExtraParts(
const NativeWindowVisibilityBrowserMainExtraParts&) = delete;
NativeWindowVisibilityBrowserMainExtraParts& operator=(
const NativeWindowVisibilityBrowserMainExtraParts&) = delete;
~NativeWindowVisibilityBrowserMainExtraParts() override = default;
// ChromeBrowserMainExtraParts:
void PostProfileInit(Profile* profile, bool is_initial_profile) override {
// The setup below is intended to run for only the initial profile.
if (!is_initial_profile) {
return;
}
gfx::NativeWindow window =
LoginDisplayHost::default_host()->GetNativeWindow();
if (window) {
observer_->Observe(window);
}
}
private:
raw_ptr<NativeWindowVisibilityObserver, DanglingUntriaged> observer_;
};
class OobeEndToEndTestSetupMixin : public InProcessBrowserTestMixin {
public:
struct Parameters {
bool is_tablet;
bool is_quick_unlock_enabled;
bool hide_shelf_controls_in_tablet_mode;
ArcState arc_state;
std::string ToString() const {
return std::string("{is_tablet: ") + (is_tablet ? "true" : "false") +
", is_quick_unlock_enabled: " +
(is_quick_unlock_enabled ? "true" : "false") +
", hide_shelf_controls_in_tablet_mode: " +
(hide_shelf_controls_in_tablet_mode ? "true" : "false") +
", arc_state: " + ArcStateToString(arc_state) + "}";
}
};
explicit OobeEndToEndTestSetupMixin(
InProcessBrowserTestMixinHost* mixin_host,
const std::tuple<bool, bool, bool, ArcState>& parameters)
: InProcessBrowserTestMixin(mixin_host) {
std::tie(params_.is_tablet, params_.is_quick_unlock_enabled,
params_.hide_shelf_controls_in_tablet_mode, params_.arc_state) =
parameters;
std::vector<base::test::FeatureRef> enabled_features = {
ash::features::kFeatureManagementOobeAiIntro,
ash::features::kFeatureManagementOobeGeminiIntro,
};
std::vector<base::test::FeatureRef> disabled_features;
if (params_.hide_shelf_controls_in_tablet_mode) {
enabled_features.push_back(features::kHideShelfControlsInTabletMode);
} else {
disabled_features.push_back(features::kHideShelfControlsInTabletMode);
}
feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
OobeEndToEndTestSetupMixin(const OobeEndToEndTestSetupMixin&) = delete;
OobeEndToEndTestSetupMixin& operator=(const OobeEndToEndTestSetupMixin&) =
delete;
~OobeEndToEndTestSetupMixin() override = default;
// InProcessBrowserTestMixin:
void SetUp() override {
LOG(INFO) << "OOBE end-to-end test started with params "
<< params_.ToString();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
if (params_.is_tablet) {
// Makes the device capable to entering tablet mode.
command_line->AppendSwitch(switches::kAshEnableTabletMode);
// Having an active internal display so that tablet mode does not end
// on display config change.
command_line->AppendSwitch(::switches::kUseFirstDisplayAsInternal);
}
if (params_.arc_state != ArcState::kNotAvailable) {
arc::SetArcAvailableCommandLineForTesting(command_line);
}
// This will change the verification key to be used by the
// CloudPolicyValidator. It will allow for the policy provided by the
// PolicyBuilder to pass the signature validation.
command_line->AppendSwitchASCII(
policy::switches::kPolicyVerificationKey,
policy::PolicyBuilder::GetEncodedPolicyVerificationKey());
}
void SetUpInProcessBrowserTestFixture() override {
if (params_.is_quick_unlock_enabled) {
test_api_ = std::make_unique<quick_unlock::TestApi>(
/*override_quick_unlock=*/true);
test_api_->EnableFingerprintByPolicy(quick_unlock::Purpose::kAny);
test_api_->EnablePinByPolicy(quick_unlock::Purpose::kAny);
}
if (params_.arc_state != ArcState::kNotAvailable) {
recommend_apps_fetcher_factory_ =
std::make_unique<apps::ScopedTestRecommendAppsFetcherFactory>(
base::BindRepeating(&CreateRecommendAppsFetcher));
}
}
void SetUpOnMainThread() override {
if (params_.is_tablet) {
ShellTestApi().SetTabletModeEnabledForTest(true);
}
if (params_.arc_state != ArcState::kNotAvailable) {
// Init ArcSessionManager for testing.
arc::ArcServiceLauncher::Get()->ResetForTesting();
arc::ArcSessionManager::Get()->SetArcSessionRunnerForTesting(
std::make_unique<arc::ArcSessionRunner>(
base::BindRepeating(arc::FakeArcSession::Create)));
arc::ExpandPropertyFilesForTesting(arc::ArcSessionManager::Get());
}
}
void TearDownInProcessBrowserTestFixture() override {
recommend_apps_fetcher_factory_.reset();
}
bool is_tablet() const { return params_.is_tablet; }
bool is_quick_unlock_enabled() const {
return params_.is_quick_unlock_enabled;
}
bool hide_shelf_controls_in_tablet_mode() const {
return params_.hide_shelf_controls_in_tablet_mode;
}
ArcState arc_state() const { return params_.arc_state; }
private:
Parameters params_;
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<apps::ScopedTestRecommendAppsFetcherFactory>
recommend_apps_fetcher_factory_;
std::unique_ptr<quick_unlock::TestApi> test_api_;
};
} // namespace
class OobeInteractiveUITest : public OobeBaseTest,
public ::testing::WithParamInterface<
std::tuple<bool, bool, bool, ArcState>> {
public:
OobeInteractiveUITest(const OobeInteractiveUITest&) = delete;
OobeInteractiveUITest& operator=(const OobeInteractiveUITest&) = delete;
OobeInteractiveUITest() {
histogram_tester_ = std::make_unique<base::HistogramTester>();
}
~OobeInteractiveUITest() override = default;
// OobeBaseTest:
void SetUpOnMainThread() override {
OobeBaseTest::SetUpOnMainThread();
fake_gaia_.SetupFakeGaiaForLoginWithDefaults();
}
void TearDownOnMainThread() override {
// If the login display is still showing, exit gracefully.
if (LoginDisplayHost::default_host()) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&chrome::AttemptExit));
RunUntilBrowserProcessQuits();
}
OobeBaseTest::TearDownOnMainThread();
}
void WaitForLoginDisplayHostShutdown() {
if (!LoginDisplayHost::default_host()) {
return;
}
LOG(INFO) << "OobeInteractiveUITest: Waiting for LoginDisplayHost to "
"shut down.";
test::TestPredicateWaiter(base::BindRepeating([]() {
return !LoginDisplayHost::default_host();
})).Wait();
LOG(INFO) << "OobeInteractiveUITest: LoginDisplayHost is down.";
}
void PerformStepsBeforeEnrollmentCheck();
void PerformSessionSignInSteps();
void SimpleEndToEnd();
const OobeEndToEndTestSetupMixin* test_setup() const { return &setup_; }
base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
private:
void ForceBrandedBuild() const;
FakeGaiaMixin fake_gaia_{&mixin_host_};
FakeEulaMixin fake_eula_{&mixin_host_, embedded_test_server()};
FakeArcTosMixin fake_arc_tos_{&mixin_host_, embedded_test_server()};
OobeEndToEndTestSetupMixin setup_{&mixin_host_, GetParam()};
std::unique_ptr<base::HistogramTester> histogram_tester_;
};
void OobeInteractiveUITest::ForceBrandedBuild() const {
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
}
void OobeInteractiveUITest::PerformStepsBeforeEnrollmentCheck() {
histogram_tester()->ExpectUniqueSample("OOBE.OobeFlowStatus", 0 /*Started*/,
1);
ForceBrandedBuild();
test::WaitForWelcomeScreen();
RunWelcomeScreenChecks();
test::TapWelcomeNext();
test::WaitForNetworkSelectionScreen();
RunNetworkSelectionScreenChecks();
test::TapNetworkSelectionNext();
test::WaitForUpdateScreen();
test::ExitUpdateScreenNoUpdate();
}
void OobeInteractiveUITest::PerformSessionSignInSteps() {
ForceBrandedBuild();
if (GetFirstSigninScreen() == UserCreationView::kScreenId) {
test::WaitForUserCreationScreen();
if (features::IsOobeSoftwareUpdateEnabled()) {
test::TapForPersonalUseCrRadioButton();
test::TapUserCreationNext();
HandleConsumerUpdateScreen();
} else {
test::TapUserCreationNext();
}
if (features::IsOobeGaiaInfoScreenEnabled()) {
HandleGaiaInfoScreen();
}
}
WaitForGaiaSignInScreen();
LogInAsRegularUser();
test::WaitForConsolidatedConsentScreen();
histogram_tester()->ExpectUniqueSample(
"OOBE.OnboardingFlowStatus.FirstOnboarding", 0 /*Started*/, 1);
histogram_tester()->ExpectTotalCount("OOBE.OobeStartToOnboardingStartTime",
1);
RunConsolidatedConsentScreenChecks();
test::TapConsolidatedConsentAccept();
test::WaitForSyncConsentScreen();
RunSyncConsentScreenChecks();
test::ExitScreenSyncConsent();
HandlePasswordSelectionScreen();
if (test_setup()->is_quick_unlock_enabled()) {
test::WaitForFingerprintScreen();
RunFingerprintScreenChecks();
test::ExitFingerprintPinSetupScreen();
}
if (test_setup()->is_tablet()) {
test::WaitForPinSetupScreen();
RunPinSetupScreenChecks();
test::ExitPinSetupScreen();
}
if (test_setup()->arc_state() != ArcState::kNotAvailable) {
HandleRecommendAppsScreen();
HandleAppDownloadingScreen();
}
if (ash::features::IsOobeAiIntroEnabled()) {
HandleAiIntroScreen();
}
HandleGeminiIntroScreen();
if (!features::IsOobeSkipAssistantEnabled()) {
HandleAssistantOptInScreen();
}
if (test_setup()->is_tablet() &&
test_setup()->hide_shelf_controls_in_tablet_mode()) {
HandleGestureNavigationScreen();
}
if (features::IsOobeChoobeEnabled()) {
HandleChoobeFlow();
} else {
HandleThemeSelectionScreen();
}
HandleMarketingOptInScreen();
histogram_tester()->ExpectBucketCount("OOBE.OobeFlowStatus", 1 /*Completed*/,
1);
histogram_tester()->ExpectBucketCount(
"OOBE.OnboardingFlowStatus.FirstOnboarding", 1 /*Completed*/, 1);
histogram_tester()->ExpectTotalCount("OOBE.OobeFlowDuration", 1);
histogram_tester()->ExpectTotalCount(
"OOBE.OnboardingFlowDuration.FirstOnboarding", 1);
}
void OobeInteractiveUITest::SimpleEndToEnd() {
test::SetFakeTouchpadDevice();
PerformStepsBeforeEnrollmentCheck();
PerformSessionSignInSteps();
WaitForLoginDisplayHostShutdown();
}
// Disabled on *San bots since they time out.
// crbug.com/1260131: SimpleEndToEnd is flaky on builder "linux-chromeos-dbg"
#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER) || \
defined(LEAK_SANITIZER) || !defined(NDEBUG)
#define MAYBE_SimpleEndToEnd DISABLED_SimpleEndToEnd
#else
#define MAYBE_SimpleEndToEnd SimpleEndToEnd
#endif
// Note that this probably the largest test that is run on ChromeOS, and it
// might be running close to time limits especially on instrumented builds.
// As such it might sometimes cause flakiness.
// Please do not disable it for whole ChromeOS, only for specific instrumented
// bots. Another alternative is to increase respective multiplier in
// base/test/test_timeouts.h.
IN_PROC_BROWSER_TEST_P(OobeInteractiveUITest, MAYBE_SimpleEndToEnd) {
SimpleEndToEnd();
}
INSTANTIATE_TEST_SUITE_P(
All,
OobeInteractiveUITest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(ArcState::kNotAvailable,
ArcState::kAcceptTerms)));
class OobeZeroTouchInteractiveUITest : public OobeInteractiveUITest {
public:
OobeZeroTouchInteractiveUITest() = default;
OobeZeroTouchInteractiveUITest(const OobeZeroTouchInteractiveUITest&) =
delete;
OobeZeroTouchInteractiveUITest& operator=(
const OobeZeroTouchInteractiveUITest&) = delete;
~OobeZeroTouchInteractiveUITest() override = default;
void SetUpOnMainThread() override {
AttestationClient::Get()
->GetTestInterface()
->AllowlistSignSimpleChallengeKey(
/*username=*/"", attestation::kEnterpriseEnrollmentKey);
OobeInteractiveUITest::SetUpOnMainThread();
policy_test_server_mixin_.ConfigureFakeStatisticsForZeroTouch(
&fake_statistics_provider_);
}
void SetUpCommandLine(base::CommandLine* command_line) override {
OobeInteractiveUITest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableInitialEnrollment,
policy::AutoEnrollmentTypeChecker::kInitialEnrollmentAlways);
// TODO(b/353731379): Remove when removing legacy state determination code.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationNever);
}
void ZeroTouchEndToEnd();
private:
EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_};
test::EnrollmentUIMixin enrollment_ui_{&mixin_host_};
system::ScopedFakeStatisticsProvider fake_statistics_provider_;
attestation::ScopedStubAttestationFeatures attestation_features_;
};
void OobeZeroTouchInteractiveUITest::ZeroTouchEndToEnd() {
base::ScopedAllowBlockingForTesting allow_io;
test::SetFakeTouchpadDevice();
policy_test_server_mixin_.SetupZeroTouchForcedEnrollment();
WizardController::default_controller()
->GetAutoEnrollmentControllerForTesting()
->SetRlweClientFactoryForTesting(
policy::psm::testing::CreateClientFactory());
PerformStepsBeforeEnrollmentCheck();
test::WaitForEnrollmentScreen();
enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSuccess);
auto login_screen_waiter = std::make_unique<LoginOrLockScreenVisibleWaiter>();
enrollment_ui_.LeaveSuccessScreen();
login_screen_waiter->WaitEvenIfShown();
PerformSessionSignInSteps();
WaitForLoginDisplayHostShutdown();
}
// crbug.com/997987. Disabled on MSAN since they time out.
// crbug.com/1055853: EndToEnd is flaky on Linux Chromium OS ASan LSan
#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER) || \
defined(LEAK_SANITIZER) || !defined(NDEBUG)
#define MAYBE_EndToEnd DISABLED_EndToEnd
#else
#define MAYBE_EndToEnd EndToEnd
#endif
// Note that this probably the largest test that is run on ChromeOS, and it
// might be running close to time limits especially on instrumented builds.
// As such it might sometimes cause flakiness.
// Please do not disable it for whole ChromeOS, only for specific instrumented
// bots. Another alternative is to increase respective multiplier in
// base/test/test_timeouts.h.
IN_PROC_BROWSER_TEST_P(OobeZeroTouchInteractiveUITest, MAYBE_EndToEnd) {
ZeroTouchEndToEnd();
}
INSTANTIATE_TEST_SUITE_P(
All,
OobeZeroTouchInteractiveUITest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(ArcState::kNotAvailable,
ArcState::kAcceptTerms)));
class PublicSessionOobeTest : public MixinBasedInProcessBrowserTest,
public ::testing::WithParamInterface<
std::tuple<bool, bool, bool, ArcState>> {
public:
PublicSessionOobeTest()
: PublicSessionOobeTest(false /*requires_terms_of_service*/) {}
explicit PublicSessionOobeTest(bool requires_terms_of_service)
: requires_terms_of_service_(requires_terms_of_service),
observer_(std::make_unique<NativeWindowVisibilityObserver>()) {
// Prevents Chrome from starting to quit right after login display is
// finalized.
login_manager_.SetShouldLaunchBrowser(true);
}
~PublicSessionOobeTest() override = default;
void SetUpInProcessBrowserTestFixture() override {
std::unique_ptr<ScopedDevicePolicyUpdate> device_policy_update =
device_state_.RequestDevicePolicyUpdate();
const std::string kAccountId = "public-session@test";
enterprise_management::DeviceLocalAccountsProto* const
device_local_accounts = device_policy_update->policy_payload()
->mutable_device_local_accounts();
// Add public session account.
enterprise_management::DeviceLocalAccountInfoProto* const account =
device_local_accounts->add_account();
account->set_account_id(kAccountId);
account->set_type(enterprise_management::DeviceLocalAccountInfoProto::
ACCOUNT_TYPE_PUBLIC_SESSION);
// Set the public session to auto-launch.
device_local_accounts->set_auto_login_id(kAccountId);
device_policy_update.reset();
std::unique_ptr<ScopedUserPolicyUpdate> device_local_account_policy_update =
device_state_.RequestDeviceLocalAccountPolicyUpdate(kAccountId);
// Specify terms of service if needed.
if (requires_terms_of_service_) {
device_local_account_policy_update->policy_payload()
->mutable_termsofserviceurl()
->set_value(embedded_test_server()
->GetURL("/chromeos/enterprise/tos.txt")
.spec());
}
device_local_account_policy_update.reset();
MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
}
void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
MixinBasedInProcessBrowserTest::CreatedBrowserMainParts(parts);
static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
std::make_unique<NativeWindowVisibilityBrowserMainExtraParts>(
observer_.get()));
}
void TearDownOnMainThread() override {
observer_.reset();
MixinBasedInProcessBrowserTest::TearDownOnMainThread();
}
bool DialogWasVisible() { return observer_->was_visible(); }
LoginManagerMixin login_manager_{&mixin_host_, {}};
private:
const bool requires_terms_of_service_;
std::unique_ptr<NativeWindowVisibilityObserver> observer_;
OobeEndToEndTestSetupMixin setup_{&mixin_host_, GetParam()};
DeviceStateMixin device_state_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
};
IN_PROC_BROWSER_TEST_P(PublicSessionOobeTest, NoTermsOfService) {
login_manager_.WaitForActiveSession();
// Check that the dialog was never shown.
EXPECT_FALSE(DialogWasVisible());
}
INSTANTIATE_TEST_SUITE_P(
All,
PublicSessionOobeTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(ArcState::kNotAvailable)));
class PublicSessionWithTermsOfServiceOobeTest : public PublicSessionOobeTest {
public:
PublicSessionWithTermsOfServiceOobeTest()
: PublicSessionOobeTest(true /*requires_terms_od_service*/) {}
~PublicSessionWithTermsOfServiceOobeTest() override = default;
// Use embedded test server to serve Public session Terms of Service.
EmbeddedTestServerSetupMixin embedded_test_server_setup_{
&mixin_host_, embedded_test_server()};
};
IN_PROC_BROWSER_TEST_P(PublicSessionWithTermsOfServiceOobeTest,
AcceptTermsOfService) {
OobeScreenWaiter(TermsOfServiceScreenView::kScreenId).Wait();
test::OobeJS()
.CreateWaiter(
test::GetOobeElementPath({"terms-of-service", "acceptButton"}))
->Wait();
test::OobeJS().ClickOnPath({"terms-of-service", "acceptButton"});
OobeScreenExitWaiter(TermsOfServiceScreenView::kScreenId).Wait();
login_manager_.WaitForActiveSession();
}
INSTANTIATE_TEST_SUITE_P(
All,
PublicSessionWithTermsOfServiceOobeTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(ArcState::kNotAvailable)));
class EphemeralUserOobeTest : public OobeBaseTest,
public ::testing::WithParamInterface<
std::tuple<bool, bool, bool, ArcState>> {
public:
EphemeralUserOobeTest() { login_manager_.SetShouldLaunchBrowser(true); }
~EphemeralUserOobeTest() override = default;
// OobeBaseTest:
void SetUpInProcessBrowserTestFixture() override {
std::unique_ptr<ScopedDevicePolicyUpdate> device_policy_update =
device_state_.RequestDevicePolicyUpdate();
device_policy_update->policy_payload()
->mutable_ephemeral_users_enabled()
->set_ephemeral_users_enabled(true);
device_policy_update.reset();
OobeBaseTest::SetUpInProcessBrowserTestFixture();
}
void SetUpOnMainThread() override {
OobeBaseTest::SetUpOnMainThread();
fake_gaia_.SetupFakeGaiaForLoginWithDefaults();
}
void WaitForActiveSession() { login_manager_.WaitForActiveSession(); }
const OobeEndToEndTestSetupMixin* test_setup() const { return &setup_; }
private:
// Fake GAIA setup.
FakeGaiaMixin fake_gaia_{&mixin_host_};
LoginManagerMixin login_manager_{&mixin_host_, {}};
// Fake Arc server and EULA server.
FakeArcTosMixin fake_arc_tos_{&mixin_host_, embedded_test_server()};
FakeEulaMixin fake_eula_{&mixin_host_, embedded_test_server()};
OobeEndToEndTestSetupMixin setup_{&mixin_host_, GetParam()};
DeviceStateMixin device_state_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
};
// In this test we login as a regular user, which means it is not affilated
// with the domain of the device. Thus we still need a consent from user.
IN_PROC_BROWSER_TEST_P(EphemeralUserOobeTest, RegularEphemeralUser) {
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
WaitForGaiaSignInScreen();
LogInAsRegularUser();
test::WaitForConsolidatedConsentScreen();
RunConsolidatedConsentScreenChecks();
test::TapConsolidatedConsentAccept();
test::WaitForSyncConsentScreen();
RunSyncConsentScreenChecks();
test::ExitScreenSyncConsent();
if (test_setup()->arc_state() != ArcState::kNotAvailable) {
HandleRecommendAppsScreen();
HandleAppDownloadingScreen();
}
if (ash::features::IsOobeAiIntroEnabled()) {
HandleAiIntroScreen();
}
HandleGeminiIntroScreen();
HandleThemeSelectionScreen();
WaitForActiveSession();
}
INSTANTIATE_TEST_SUITE_P(
All,
EphemeralUserOobeTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(ArcState::kNotAvailable,
ArcState::kAcceptTerms)));
class OobeFlexInteractiveUITest
: public OobeBaseTest,
public ::testing::WithParamInterface<::tpm_manager::TpmManagerStatus> {
public:
OobeFlexInteractiveUITest() = default;
OobeFlexInteractiveUITest(const OobeFlexInteractiveUITest&) = delete;
OobeFlexInteractiveUITest& operator=(const OobeFlexInteractiveUITest&) =
delete;
~OobeFlexInteractiveUITest() override = default;
// EnrollmentScreenTest:
void SetUpOnMainThread() override {
EnrollmentScreen* enrollment_screen = EnrollmentScreen::Get(
WizardController::default_controller()->screen_manager());
original_tpm_check_callback_ =
enrollment_screen->get_tpm_ownership_callback_for_testing();
enrollment_screen->set_tpm_ownership_callback_for_testing(base::BindOnce(
&OobeFlexInteractiveUITest::HandleTakeTPMOwnershipResponse,
base::Unretained(this)));
OobeBaseTest::SetUpOnMainThread();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kTpmIsDynamic);
OobeBaseTest::SetUpCommandLine(command_line);
// This will change the verification key to be used by the
// CloudPolicyValidator. It will allow for the policy provided by the
// PolicyBuilder to pass the signature validation.
command_line->AppendSwitchASCII(
policy::switches::kPolicyVerificationKey,
policy::PolicyBuilder::GetEncodedPolicyVerificationKey());
}
test::EnrollmentUIMixin enrollment_ui_{&mixin_host_};
private:
void HandleTakeTPMOwnershipResponse(
const ::tpm_manager::TakeOwnershipReply& reply) {
EXPECT_FALSE(tpm_reply_.has_value());
tpm_reply_ = reply;
// Here we substitute fake reply with status that we want to test.
tpm_reply_.value().set_status(GetParam());
if (original_tpm_check_callback_) {
std::move(original_tpm_check_callback_).Run(tpm_reply_.value());
}
}
EnrollmentScreen::TpmStatusCallback original_tpm_check_callback_;
std::optional<::tpm_manager::TakeOwnershipReply> tpm_reply_;
};
// Verify that ChromeOS Flex behaves as expected on devices with different TPM
// configurations.
IN_PROC_BROWSER_TEST_P(OobeFlexInteractiveUITest, SmokeEnroll) {
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
test::WaitForWelcomeScreen();
RunWelcomeScreenChecks();
test::TapWelcomeNext();
test::WaitForNetworkSelectionScreen();
RunNetworkSelectionScreenChecks();
test::TapNetworkSelectionNext();
test::WaitForUpdateScreen();
test::ExitUpdateScreenNoUpdate();
LoginDisplayHost* host = LoginDisplayHost::default_host();
host->HandleAccelerator(LoginAcceleratorAction::kStartEnrollment);
test::WaitForEnrollmentScreen();
switch (GetParam()) {
case ::tpm_manager::STATUS_SUCCESS:
case ::tpm_manager::STATUS_NOT_AVAILABLE:
enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSignin);
return;
case ::tpm_manager::STATUS_DBUS_ERROR: {
OobeScreenExitWaiter(TpmErrorView::kScreenId).Wait();
test::OobeJS().ExpectVisiblePath({"tpm-error-message", "restartButton"});
ash::test::TapOnPathAndWaitForOobeToBeDestroyed(
{"tpm-error-message", "restartButton"});
EXPECT_EQ(
chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(),
1);
return;
}
case ::tpm_manager::STATUS_DEVICE_ERROR: {
OobeScreenExitWaiter(TpmErrorView::kScreenId).Wait();
test::OobeJS().ExpectVisiblePath({"tpm-error-message", "restartButton"});
ash::test::TapOnPathAndWaitForOobeToBeDestroyed(
{"tpm-error-message", "restartButton"});
EXPECT_EQ(
chromeos::FakePowerManagerClient::Get()->num_request_restart_calls(),
1);
return;
}
}
}
INSTANTIATE_TEST_SUITE_P(All,
OobeFlexInteractiveUITest,
::testing::Values(::tpm_manager::STATUS_SUCCESS,
::tpm_manager::STATUS_DEVICE_ERROR,
::tpm_manager::STATUS_NOT_AVAILABLE,
::tpm_manager::STATUS_DBUS_ERROR));
} // namespace ash