blob: 3147416673d532de6cdb3f524d6db9462d7d6a48 [file] [log] [blame]
// Copyright 2012 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/wizard_controller.h"
#include <memory>
#include <tuple>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/login_screen_test_api.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/functional/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/run_until.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "build/build_config.h"
#include "chrome/browser/ash/accessibility/accessibility_manager.h"
#include "chrome/browser/ash/base/locale_util.h"
#include "chrome/browser/ash/login/demo_mode/demo_mode_test_utils.h"
#include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h"
#include "chrome/browser/ash/login/enrollment/enrollment_screen.h"
#include "chrome/browser/ash/login/enrollment/mock_auto_enrollment_check_screen.h"
#include "chrome/browser/ash/login/enrollment/mock_enrollment_screen.h"
#include "chrome/browser/ash/login/existing_user_controller.h"
#include "chrome/browser/ash/login/login_manager_test.h"
#include "chrome/browser/ash/login/login_wizard.h"
#include "chrome/browser/ash/login/oobe_configuration.h"
#include "chrome/browser/ash/login/oobe_screen.h"
#include "chrome/browser/ash/login/screens/consolidated_consent_screen.h"
#include "chrome/browser/ash/login/screens/device_disabled_screen.h"
#include "chrome/browser/ash/login/screens/error_screen.h"
#include "chrome/browser/ash/login/screens/hid_detection_screen.h"
#include "chrome/browser/ash/login/screens/mock_consolidated_consent_screen.h"
#include "chrome/browser/ash/login/screens/mock_demo_preferences_screen.h"
#include "chrome/browser/ash/login/screens/mock_demo_setup_screen.h"
#include "chrome/browser/ash/login/screens/mock_device_disabled_screen_view.h"
#include "chrome/browser/ash/login/screens/mock_enable_adb_sideloading_screen.h"
#include "chrome/browser/ash/login/screens/mock_enable_debugging_screen.h"
#include "chrome/browser/ash/login/screens/mock_network_screen.h"
#include "chrome/browser/ash/login/screens/mock_update_screen.h"
#include "chrome/browser/ash/login/screens/mock_welcome_screen.h"
#include "chrome/browser/ash/login/screens/mock_wrong_hwid_screen.h"
#include "chrome/browser/ash/login/screens/remote_activity_notification_screen.h"
#include "chrome/browser/ash/login/screens/reset_screen.h"
#include "chrome/browser/ash/login/screens/welcome_screen.h"
#include "chrome/browser/ash/login/screens/wrong_hwid_screen.h"
#include "chrome/browser/ash/login/startup_utils.h"
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/js_checker.h"
#include "chrome/browser/ash/login/test/local_state_mixin.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/login/test/network_portal_detector_mixin.h"
#include "chrome/browser/ash/login/test/oobe_base_test.h"
#include "chrome/browser/ash/login/test/oobe_configuration_waiter.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/test_predicate_waiter.h"
#include "chrome/browser/ash/login/test/user_auth_config.h"
#include "chrome/browser/ash/net/network_portal_detector_test_impl.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_client.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_controller.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_state.h"
#include "chrome/browser/ash/policy/enrollment/auto_enrollment_type_checker.h"
#include "chrome/browser/ash/policy/enrollment/enrollment_config.h"
#include "chrome/browser/ash/policy/enrollment/enrollment_state_fetcher.h"
#include "chrome/browser/ash/policy/enrollment/fake_auto_enrollment_client.h"
#include "chrome/browser/ash/policy/server_backed_state/server_backed_device_state.h"
#include "chrome/browser/ash/policy/server_backed_state/server_backed_state_keys_broker.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/lifetime/termination_notification.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/login/login_display_host.h"
#include "chrome/browser/ui/ash/login/webui_login_view.h"
#include "chrome/browser/ui/webui/ash/login/consolidated_consent_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/display_size_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/error_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/gesture_navigation_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/local_state_error_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/marketing_opt_in_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/oobe_ui.h"
#include "chrome/browser/ui/webui/ash/login/remote_activity_notification_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/reset_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/update_required_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/user_creation_screen_handler.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "chromeos/ash/components/dbus/device_management/fake_install_attributes_client.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/ash/components/dbus/shill/fake_shill_manager_client.h"
#include "chromeos/ash/components/dbus/system_clock/system_clock_client.h"
#include "chromeos/ash/components/geolocation/simple_geolocation_provider.h"
#include "chromeos/ash/components/http_auth_dialog/http_auth_dialog.h"
#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/settings/timezone_settings.h"
#include "chromeos/ash/components/system/fake_statistics_provider.h"
#include "chromeos/ash/components/system/statistics_provider.h"
#include "chromeos/ash/components/timezone/timezone_request.h"
#include "chromeos/dbus/constants/dbus_switches.h"
#include "chromeos/test/chromeos_test_utils.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/testing_pref_store.h"
#include "components/session_manager/core/session_manager.h"
#include "components/session_manager/session_manager_types.h"
#include "content/public/common/content_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 "google_apis/gaia/gaia_id.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "remoting/host/chromeos/features.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/source/common/unicode/locid.h"
#include "third_party/icu/source/i18n/unicode/timezone.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
namespace {
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsNull;
using ::testing::Mock;
using ::testing::NotNull;
const char kDMServerURLPrefix[] =
"https://m.google.com/devicemanagement/data/api";
const char kGeolocationResponseBody[] =
"{\n"
" \"location\": {\n"
" \"lat\": 51.0,\n"
" \"lng\": -0.1\n"
" },\n"
" \"accuracy\": 1200.4\n"
"}";
// Timezone should not match kGeolocationResponseBody to check that exactly
// this value will be used.
const char kTimezoneResponseBody[] =
"{\n"
" \"dstOffset\" : 0.0,\n"
" \"rawOffset\" : -32400.0,\n"
" \"status\" : \"OK\",\n"
" \"timeZoneId\" : \"America/Anchorage\",\n"
" \"timeZoneName\" : \"Pacific Standard Time\"\n"
"}";
const char kDisabledMessage[] = "This device has been disabled.";
const test::UIPath kGuestSessionLink = {"error-message",
"error-guest-signin-fix-network"};
constexpr policy::AutoEnrollmentState kAutoEnrollmentConnectionError =
base::unexpected(policy::AutoEnrollmentDMServerError{
.dm_error = policy::DM_STATUS_REQUEST_FAILED,
.network_error = net::ERR_CONNECTION_REFUSED});
constexpr policy::AutoEnrollmentState kAutoEnrollmentServerError =
base::unexpected(policy::AutoEnrollmentDMServerError{
.dm_error = policy::DM_STATUS_TEMPORARY_UNAVAILABLE});
constexpr policy::AutoEnrollmentState kAutoEnrollmentStateKeysRetrievalError =
base::unexpected(policy::AutoEnrollmentStateKeysRetrievalError{});
// Matches on the mode parameter of an EnrollmentConfig object.
MATCHER_P(EnrollmentModeMatches, mode, "") {
return arg.mode == mode;
}
template <typename Error>
policy::AutoEnrollmentState ToAutoEnrollmentState(Error error) {
return base::unexpected(error);
}
class PrefStoreStub : public TestingPrefStore {
public:
// TestingPrefStore overrides:
PrefReadError GetReadError() const override {
return PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
}
bool IsInitializationComplete() const override { return true; }
private:
~PrefStoreStub() override = default;
};
// Used to set up a `FakeAutoEnrollmentClientFactory` for the duration of a
// test.
class ScopedFakeAutoEnrollmentClientFactory {
public:
explicit ScopedFakeAutoEnrollmentClientFactory(
policy::AutoEnrollmentController* controller)
: controller_(controller) {
auto fake_auto_enrollment_client_factory =
std::make_unique<policy::FakeAutoEnrollmentClient::FactoryImpl>(
base::BindRepeating(&ScopedFakeAutoEnrollmentClientFactory::
OnFakeAutoEnrollmentClientCreated,
base::Unretained(this)));
controller_->SetAutoEnrollmentClientFactoryForTesting(
std::move(fake_auto_enrollment_client_factory));
}
ScopedFakeAutoEnrollmentClientFactory(
const ScopedFakeAutoEnrollmentClientFactory&) = delete;
ScopedFakeAutoEnrollmentClientFactory& operator=(
const ScopedFakeAutoEnrollmentClientFactory&) = delete;
~ScopedFakeAutoEnrollmentClientFactory() {
controller_->SetAutoEnrollmentClientFactoryForTesting(nullptr);
}
// Waits until the `policy::AutoEnrollmentController` has requested the
// creation of an `AutoEnrollmentClient`. Returns the created
// `AutoEnrollmentClient`. If an `AutoEnrollmentClient` has already been
// created, returns immediately. Note: The returned instance is owned by
// `policy::AutoEnrollmentController`.
policy::FakeAutoEnrollmentClient* WaitAutoEnrollmentClientCreated() {
if (created_auto_enrollment_client_) {
return created_auto_enrollment_client_;
}
base::RunLoop run_loop;
run_on_auto_enrollment_client_created_ = run_loop.QuitClosure();
run_loop.Run();
return created_auto_enrollment_client_;
}
// Resets the cached `AutoEnrollmentClient`, so another `AutoEnrollmentClient`
// may be created through this factory.
void Reset() { created_auto_enrollment_client_ = nullptr; }
private:
// Called when `fake_auto_enrollment_client_factory_` was asked to create an
// `AutoEnrollmentClient`.
void OnFakeAutoEnrollmentClientCreated(
policy::FakeAutoEnrollmentClient* auto_enrollment_client) {
// Only allow an AutoEnrollmentClient to be created when the test expects
// it. The test should call `Reset` to expect a new `AutoEnrollmentClient`
// to be created.
EXPECT_FALSE(created_auto_enrollment_client_);
created_auto_enrollment_client_ = auto_enrollment_client;
if (run_on_auto_enrollment_client_created_) {
std::move(run_on_auto_enrollment_client_created_).Run();
}
}
// The `policy::AutoEnrollmentController` which is using
// `fake_auto_enrollment_client_factory_`.
raw_ptr<policy::AutoEnrollmentController> controller_;
raw_ptr<policy::FakeAutoEnrollmentClient> created_auto_enrollment_client_ =
nullptr;
base::OnceClosure run_on_auto_enrollment_client_created_;
};
// Used to set up a fake `EnrollmentStateFetcher::Factory` for the duration of a
// test, which invokes result callback with the specified enrollment state.
class ScopedEnrollmentStateFetcherFactory {
public:
explicit ScopedEnrollmentStateFetcherFactory(
policy::AutoEnrollmentController* controller)
: controller_(controller) {
controller_->SetEnrollmentStateFetcherFactoryForTesting(base::BindRepeating(
&ScopedEnrollmentStateFetcherFactory::Create, base::Unretained(this)));
}
ScopedEnrollmentStateFetcherFactory(
const ScopedEnrollmentStateFetcherFactory&) = delete;
ScopedEnrollmentStateFetcherFactory& operator=(
const ScopedEnrollmentStateFetcherFactory&) = delete;
~ScopedEnrollmentStateFetcherFactory() {
controller_->SetEnrollmentStateFetcherFactoryForTesting(
base::NullCallback());
}
// Waits until the `policy::AutoEnrollmentController` has requested the
// creation of an `EnrollmentStateFetcher`. If an `EnrollmentStateFetcher` has
// already been created, returns immediately. Note: The returned instance is
// owned by `policy::AutoEnrollmentController`.
void WaitUntilEnrollmentStateFetcherCreated() {
if (!fetcher_created_) {
base::RunLoop run_loop;
created_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
}
void ReportEnrollmentState(policy::AutoEnrollmentState state) {
ASSERT_TRUE(fetcher_created_);
ASSERT_FALSE(report_result_.is_null());
std::move(report_result_).Run(state);
base::RunLoop().RunUntilIdle();
}
void Reset() {
fetcher_created_ = false;
created_callback_.Reset();
}
private:
class MockEnrollmentStateFetcher
: public testing::StrictMock<policy::EnrollmentStateFetcher> {
public:
MOCK_METHOD(void, Start, ());
};
std::unique_ptr<policy::EnrollmentStateFetcher> Create(
base::OnceCallback<void(policy::AutoEnrollmentState)> report_result,
PrefService* local_state,
policy::EnrollmentStateFetcher::RlweClientFactory rlwe_client_factory,
policy::DeviceManagementService* device_management_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
policy::ServerBackedStateKeysBroker* state_key_broker,
ash::DeviceSettingsService* device_settings_service,
OobeConfiguration* oobe_configuration) {
// Only allow one `EnrollmentStateFetcher` to be created. The test should
// call `Reset` to expect a new `EnrollmentStateFetcher` to be created.
EXPECT_FALSE(fetcher_created_);
fetcher_created_ = true;
report_result_ = std::move(report_result);
auto fetcher = std::make_unique<MockEnrollmentStateFetcher>();
EXPECT_CALL(*fetcher, Start()).WillOnce(testing::Return());
if (!created_callback_.is_null()) {
std::move(created_callback_).Run();
}
return std::move(fetcher);
}
// The `policy::AutoEnrollmentController` which is using
// `MockEnrollmentStateFetcher`.
raw_ptr<policy::AutoEnrollmentController> controller_;
bool fetcher_created_ = false;
base::OnceCallback<void(policy::AutoEnrollmentState)> report_result_;
base::OnceClosure created_callback_;
};
struct SwitchLanguageTestData {
SwitchLanguageTestData() : result("", "", false), done(false) {}
locale_util::LanguageSwitchResult result;
bool done;
};
void OnLocaleSwitched(SwitchLanguageTestData* self,
const locale_util::LanguageSwitchResult& result) {
self->result = result;
self->done = true;
}
void RunSwitchLanguageTest(const std::string& locale,
const std::string& expected_locale,
const bool expect_success) {
SwitchLanguageTestData data;
locale_util::SwitchLanguageCallback callback(
base::BindOnce(&OnLocaleSwitched, base::Unretained(&data)));
locale_util::SwitchLanguage(locale, true, false, std::move(callback),
ProfileManager::GetActiveUserProfile());
// Token writing moves control to BlockingPool and back.
content::RunAllTasksUntilIdle();
EXPECT_EQ(data.done, true);
EXPECT_EQ(data.result.requested_locale, locale);
EXPECT_EQ(data.result.loaded_locale, expected_locale);
EXPECT_EQ(data.result.success, expect_success);
}
void SetUpCrasAndEnableChromeVox(int volume_percent, bool mute_on) {
AccessibilityManager* a11y = AccessibilityManager::Get();
CrasAudioHandler* cras = CrasAudioHandler::Get();
// Audio output is at `volume_percent` and `mute_on`. Spoken feedback
// is disabled.
cras->SetOutputVolumePercent(volume_percent);
cras->SetOutputMute(mute_on);
a11y->EnableSpokenFeedback(false);
// Spoken feedback is enabled.
a11y->EnableSpokenFeedback(true);
base::RunLoop().RunUntilIdle();
}
void QuitLoopOnAutoEnrollmentProgress(
policy::AutoEnrollmentState expected_state,
base::RunLoop* loop,
policy::AutoEnrollmentState actual_state) {
if (expected_state == actual_state) {
loop->Quit();
}
}
// Returns a string which can be put into the VPD variable
// `kRlzEmbargoEndDateKey`. If `days_offset` is 0, the return
// value represents the current day. If `days_offset` is positive, the return
// value represents `days_offset` days in the future. If `days_offset` is
// negative, the return value represents `days_offset` days in the past.
std::string GenerateEmbargoEndDate(int days_offset) {
return base::UnlocalizedTimeFormatWithPattern(
base::Time::Now() + base::Days(days_offset), "yyyy-MM-dd",
icu::TimeZone::getGMT());
}
template <typename View>
void ExpectBind(View* view) {
// TODO(jdufault): The view* api should follow the bind/unbind pattern instead
// of bind(ptr), bind(nullptr).
EXPECT_CALL(*view, MockBind(NotNull())).Times(1);
EXPECT_CALL(*view, MockBind(IsNull())).Times(1);
}
template <typename View>
void ExpectBindUnbind(View* view) {
EXPECT_CALL(*view, MockBind(NotNull())).Times(1);
EXPECT_CALL(*view, MockUnbind()).Times(1);
}
template <typename View>
void ExpectSetDelegate(View* view) {
EXPECT_CALL(*view, MockSetDelegate(NotNull())).Times(1);
EXPECT_CALL(*view, MockSetDelegate(IsNull())).Times(1);
}
template <typename Mock>
Mock* MockScreen(std::unique_ptr<Mock> mock) {
auto mock0 = mock.get();
WizardController::default_controller()->screen_manager()->SetScreenForTesting(
std::move(mock));
return mock0;
}
template <typename Mock>
Mock* MockScreenExpectLifecycle(std::unique_ptr<Mock> mock) {
auto mock0 = MockScreen(std::move(mock));
EXPECT_CALL(*mock0, ShowImpl()).Times(0);
return mock0;
}
} // namespace
class WizardControllerTest : public OobeBaseTest {
public:
WizardControllerTest(const WizardControllerTest&) = delete;
WizardControllerTest& operator=(const WizardControllerTest&) = delete;
protected:
WizardControllerTest() = default;
~WizardControllerTest() override = default;
ErrorScreen* GetErrorScreen() { return GetOobeUI()->GetErrorScreen(); }
OobeUI* GetOobeUI() { return LoginDisplayHost::default_host()->GetOobeUI(); }
content::WebContents* GetWebContents() {
LoginDisplayHost* host = LoginDisplayHost::default_host();
if (!host) {
return nullptr;
}
return host->GetOobeWebContents();
}
bool JSExecute(const std::string& script) {
return content::ExecJs(GetWebContents(), script);
}
bool JSExecuteBooleanExpression(const std::string& expression) {
return content::EvalJs(GetWebContents(), "!!(" + expression + ");")
.ExtractBool();
}
std::string JSExecuteStringExpression(const std::string& expression) {
return content::EvalJs(GetWebContents(), expression).ExtractString();
}
void CheckCurrentScreen(OobeScreenId screen) {
BaseScreen* current_screen =
WizardController::default_controller()->current_screen();
const std::string actual_screen =
current_screen ? current_screen->screen_id().name : "nullptr";
const std::string expected_screen = screen.name;
EXPECT_EQ(actual_screen, expected_screen);
}
WrongHWIDScreen* GetWrongHWIDScreen() {
return static_cast<WrongHWIDScreen*>(
WizardController::default_controller()->GetScreen(
WrongHWIDScreenView::kScreenId));
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerTest, SwitchLanguage) {
ASSERT_TRUE(WizardController::default_controller() != nullptr);
WizardController::default_controller()->AdvanceToScreen(
WelcomeView::kScreenId);
test::WaitForWelcomeScreen();
// Checking the default locale. Provided that the profile is cleared in SetUp.
EXPECT_EQ("en-US", g_browser_process->GetApplicationLocale());
EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
EXPECT_FALSE(base::i18n::IsRTL());
const std::u16string en_str =
l10n_util::GetStringUTF16(IDS_UPDATE_STATUS_TITLE);
RunSwitchLanguageTest("fr", "fr", true);
EXPECT_EQ("fr", g_browser_process->GetApplicationLocale());
EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
EXPECT_FALSE(base::i18n::IsRTL());
const std::u16string fr_str =
l10n_util::GetStringUTF16(IDS_UPDATE_STATUS_TITLE);
EXPECT_NE(en_str, fr_str);
RunSwitchLanguageTest("ar", "ar", true);
EXPECT_EQ("ar", g_browser_process->GetApplicationLocale());
EXPECT_STREQ("ar", icu::Locale::getDefault().getLanguage());
EXPECT_TRUE(base::i18n::IsRTL());
const std::u16string ar_str =
l10n_util::GetStringUTF16(IDS_UPDATE_STATUS_TITLE);
EXPECT_NE(fr_str, ar_str);
}
IN_PROC_BROWSER_TEST_F(WizardControllerTest, VolumeIsChangedForChromeVox) {
SetUpCrasAndEnableChromeVox(75 /* volume_percent */, true /* mute_on */);
// Check that output is unmuted now and at some level.
CrasAudioHandler* cras = CrasAudioHandler::Get();
ASSERT_FALSE(cras->IsOutputMuted());
ASSERT_EQ(WizardController::kMinAudibleOutputVolumePercent,
cras->GetOutputVolumePercent());
}
IN_PROC_BROWSER_TEST_F(WizardControllerTest, VolumeIsUnchangedForChromeVox) {
SetUpCrasAndEnableChromeVox(75 /* volume_percent */, false /* mute_on */);
// Check that output is unmuted now and at some level.
CrasAudioHandler* cras = CrasAudioHandler::Get();
ASSERT_FALSE(cras->IsOutputMuted());
ASSERT_EQ(75, cras->GetOutputVolumePercent());
}
IN_PROC_BROWSER_TEST_F(WizardControllerTest, VolumeIsAdjustedForChromeVox) {
SetUpCrasAndEnableChromeVox(5 /* volume_percent */, false /* mute_on */);
// Check that output is unmuted now and at some level.
CrasAudioHandler* cras = CrasAudioHandler::Get();
ASSERT_FALSE(cras->IsOutputMuted());
ASSERT_EQ(WizardController::kMinAudibleOutputVolumePercent,
cras->GetOutputVolumePercent());
}
class WizardControllerFlowTest : public WizardControllerTest {
public:
WizardControllerFlowTest(const WizardControllerFlowTest&) = delete;
WizardControllerFlowTest& operator=(const WizardControllerFlowTest&) = delete;
protected:
WizardControllerFlowTest() = default;
// WizardControllerTest:
void SetUpOnMainThread() override {
WizardControllerTest::SetUpOnMainThread();
// Make sure that OOBE is run as an "official" build.
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build =
true;
WizardController* wizard_controller =
WizardController::default_controller();
wizard_controller->SetCurrentScreen(nullptr);
WaitForOobeUI();
wizard_controller->SetSharedURLLoaderFactoryForTesting(
test_url_loader_factory_.GetSafeWeakWrapper());
SimpleGeolocationProvider::GetInstance()
->SetSharedUrlLoaderFactoryForTesting(
test_url_loader_factory_.GetSafeWeakWrapper());
// Set up the mocks for all screens.
mock_welcome_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockWelcomeScreen>(
GetOobeUI()->GetView<WelcomeScreenHandler>()->AsWeakPtr(),
base::BindRepeating(&WizardController::OnWelcomeScreenExit,
base::Unretained(wizard_controller))));
mock_demo_preferences_screen_view_ =
std::make_unique<MockDemoPreferencesScreenView>();
mock_demo_preferences_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockDemoPreferencesScreen>(
mock_demo_preferences_screen_view_->AsWeakPtr(),
base::BindRepeating(&WizardController::OnDemoPreferencesScreenExit,
base::Unretained(wizard_controller))));
device_disabled_screen_view_ =
std::make_unique<MockDeviceDisabledScreenView>();
MockScreen(std::make_unique<DeviceDisabledScreen>(
device_disabled_screen_view_->AsWeakPtr()));
EXPECT_CALL(*device_disabled_screen_view_, Show(_)).Times(0);
mock_network_screen_view_ = std::make_unique<MockNetworkScreenView>();
mock_network_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockNetworkScreen>(
mock_network_screen_view_.get()->AsWeakPtr(),
base::BindRepeating(&WizardController::OnNetworkScreenExit,
base::Unretained(wizard_controller))));
mock_update_view_ = std::make_unique<MockUpdateView>();
mock_update_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockUpdateScreen>(
mock_update_view_.get()->AsWeakPtr(), GetErrorScreen(),
base::BindRepeating(&WizardController::OnUpdateScreenExit,
base::Unretained(wizard_controller))));
mock_enrollment_screen_view_ = std::make_unique<MockEnrollmentScreenView>();
mock_enrollment_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockEnrollmentScreen>(
mock_enrollment_screen_view_->AsWeakPtr(), GetErrorScreen(),
base::BindRepeating(&WizardController::OnEnrollmentScreenExit,
base::Unretained(wizard_controller))));
mock_auto_enrollment_check_screen_view_ =
std::make_unique<MockAutoEnrollmentCheckScreenView>();
mock_auto_enrollment_check_screen_ = MockScreen(
std::make_unique<testing::NiceMock<MockAutoEnrollmentCheckScreen>>(
mock_auto_enrollment_check_screen_view_.get()->AsWeakPtr(),
GetErrorScreen(),
base::BindRepeating(
&WizardController::OnAutoEnrollmentCheckScreenExit,
base::Unretained(wizard_controller))));
mock_wrong_hwid_screen_view_ = std::make_unique<MockWrongHWIDScreenView>();
mock_wrong_hwid_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockWrongHWIDScreen>(
mock_wrong_hwid_screen_view_.get()->AsWeakPtr(),
base::BindRepeating(&WizardController::OnWrongHWIDScreenExit,
base::Unretained(wizard_controller))));
mock_enable_adb_sideloading_screen_view_ =
std::make_unique<MockEnableAdbSideloadingScreenView>();
mock_enable_adb_sideloading_screen_ = MockScreenExpectLifecycle(
std::make_unique<MockEnableAdbSideloadingScreen>(
mock_enable_adb_sideloading_screen_view_->AsWeakPtr(),
base::BindRepeating(
&WizardController::OnEnableAdbSideloadingScreenExit,
base::Unretained(wizard_controller))));
mock_enable_debugging_screen_view_ =
std::make_unique<MockEnableDebuggingScreenView>();
mock_enable_debugging_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockEnableDebuggingScreen>(
mock_enable_debugging_screen_view_.get()->AsWeakPtr(),
base::BindRepeating(&WizardController::OnEnableDebuggingScreenExit,
base::Unretained(wizard_controller))));
mock_demo_setup_screen_view_ = std::make_unique<MockDemoSetupScreenView>();
mock_demo_setup_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockDemoSetupScreen>(
mock_demo_setup_screen_view_->AsWeakPtr(),
base::BindRepeating(&WizardController::OnDemoSetupScreenExit,
base::Unretained(wizard_controller))));
mock_demo_preferences_screen_view_ =
std::make_unique<MockDemoPreferencesScreenView>();
mock_demo_preferences_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockDemoPreferencesScreen>(
mock_demo_preferences_screen_view_->AsWeakPtr(),
base::BindRepeating(&WizardController::OnDemoPreferencesScreenExit,
base::Unretained(wizard_controller))));
mock_consolidated_consent_screen_view_ =
std::make_unique<MockConsolidatedConsentScreenView>();
mock_consolidated_consent_screen_ = MockScreenExpectLifecycle(
std::make_unique<MockConsolidatedConsentScreen>(
mock_consolidated_consent_screen_view_.get()->AsWeakPtr(),
base::BindRepeating(
&WizardController::OnConsolidatedConsentScreenExit,
base::Unretained(wizard_controller))));
// Switch to the initial screen.
EXPECT_EQ(nullptr, wizard_controller->current_screen());
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
wizard_controller->AdvanceToScreen(WelcomeView::kScreenId);
}
void TearDownOnMainThread() override {
mock_welcome_screen_ = nullptr;
device_disabled_screen_view_.reset();
test_url_loader_factory_.ClearResponses();
WizardControllerTest::TearDownOnMainThread();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerTest::SetUpCommandLine(command_line);
// Default to now showing auto enrollment check screen. If you want to show
// this screen, you can override the flags.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableForcedReEnrollment,
policy::AutoEnrollmentTypeChecker::kForcedReEnrollmentNever);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableInitialEnrollment,
policy::AutoEnrollmentTypeChecker::kInitialEnrollmentNever);
}
void InitNetworkPortalDetector() {
network_portal_detector_ = new NetworkPortalDetectorTestImpl();
network_portal_detector::InitializeForTesting(network_portal_detector_);
// Default networks defaults to "eth1" in tests.
const NetworkState* default_network =
NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
ASSERT_TRUE(default_network);
network_portal_detector_->SetDefaultNetworkForTesting(
default_network->guid());
}
void WaitUntilTimezoneResolved() {
base::RunLoop loop;
if (!WizardController::default_controller()
->SetOnTimeZoneResolvedForTesting(loop.QuitClosure())) {
return;
}
loop.Run();
}
void ResetAutoEnrollmentCheckScreen() {
WizardController::default_controller()
->screen_manager()
->DeleteScreenForTesting(AutoEnrollmentCheckScreenView::kScreenId);
}
void TestControlFlowMain() {
CheckCurrentScreen(WelcomeView::kScreenId);
test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
if (base::StartsWith(
request.url.spec(),
SimpleGeolocationProvider::DefaultGeolocationProviderURL()
.spec(),
base::CompareCase::SENSITIVE)) {
test_url_loader_factory_.AddResponse(request.url.spec(),
kGeolocationResponseBody);
} else if (base::StartsWith(request.url.spec(),
DefaultTimezoneProviderURL().spec(),
base::CompareCase::SENSITIVE)) {
test_url_loader_factory_.AddResponse(request.url.spec(),
kTimezoneResponseBody);
}
}));
ASSERT_TRUE(LoginScreenTestApi::IsLoginShelfShown());
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
InitNetworkPortalDetector();
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
EXPECT_NE(SimpleGeolocationProvider::GetInstance(), nullptr);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
WaitUntilTimezoneResolved();
EXPECT_EQ(
"America/Anchorage",
base::UTF16ToUTF8(
system::TimezoneSettings::GetInstance()->GetCurrentTimezoneID()));
}
// All of the *Screen types are owned by WizardController. The views are owned
// by this test class.
raw_ptr<MockWelcomeScreen, DanglingUntriaged> mock_welcome_screen_ = nullptr;
raw_ptr<MockNetworkScreen, DanglingUntriaged> mock_network_screen_ = nullptr;
std::unique_ptr<MockNetworkScreenView> mock_network_screen_view_;
raw_ptr<MockUpdateScreen, DanglingUntriaged> mock_update_screen_ = nullptr;
std::unique_ptr<MockUpdateView> mock_update_view_;
raw_ptr<MockEnrollmentScreen, DanglingUntriaged> mock_enrollment_screen_ =
nullptr;
std::unique_ptr<MockEnrollmentScreenView> mock_enrollment_screen_view_;
// Auto enrollment check screen is a nice mock because it may or may not be
// shown depending on when asynchronous auto enrollment check finishes. Only
// add expectations for this if you are sure they are not affected by race
// conditions.
raw_ptr<testing::NiceMock<MockAutoEnrollmentCheckScreen>, DanglingUntriaged>
mock_auto_enrollment_check_screen_ = nullptr;
std::unique_ptr<MockAutoEnrollmentCheckScreenView>
mock_auto_enrollment_check_screen_view_;
raw_ptr<MockWrongHWIDScreen, DanglingUntriaged> mock_wrong_hwid_screen_ =
nullptr;
std::unique_ptr<MockWrongHWIDScreenView> mock_wrong_hwid_screen_view_;
raw_ptr<MockEnableAdbSideloadingScreen, DanglingUntriaged>
mock_enable_adb_sideloading_screen_ = nullptr;
std::unique_ptr<MockEnableAdbSideloadingScreenView>
mock_enable_adb_sideloading_screen_view_;
raw_ptr<MockEnableDebuggingScreen, DanglingUntriaged>
mock_enable_debugging_screen_ = nullptr;
std::unique_ptr<MockEnableDebuggingScreenView>
mock_enable_debugging_screen_view_;
raw_ptr<MockDemoSetupScreen, DanglingUntriaged> mock_demo_setup_screen_ =
nullptr;
std::unique_ptr<MockDemoSetupScreenView> mock_demo_setup_screen_view_;
raw_ptr<MockDemoPreferencesScreen, DanglingUntriaged>
mock_demo_preferences_screen_ = nullptr;
std::unique_ptr<MockDemoPreferencesScreenView>
mock_demo_preferences_screen_view_;
raw_ptr<MockConsolidatedConsentScreen, DanglingUntriaged>
mock_consolidated_consent_screen_ = nullptr;
std::unique_ptr<MockConsolidatedConsentScreenView>
mock_consolidated_consent_screen_view_;
std::unique_ptr<MockDeviceDisabledScreenView> device_disabled_screen_view_;
network::TestURLLoaderFactory test_url_loader_factory_;
private:
raw_ptr<NetworkPortalDetectorTestImpl, DanglingUntriaged>
network_portal_detector_ = nullptr;
std::unique_ptr<base::AutoReset<bool>> branded_build_override_;
};
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowMain) {
TestControlFlowMain();
}
// This test verifies that if WizardController fails to apply a non-critical
// update before the OOBE is marked complete, it allows the user to proceed to
// log in.
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
ControlFlowErrorUpdateNonCriticalUpdate) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
}
// This test verifies that if WizardController fails to apply a critical update
// before the OOBE is marked complete, it goes back the network selection
// screen and thus prevents the user from proceeding to log in.
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
ControlFlowErrorUpdateCriticalUpdate) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(0); // last transition
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_ERROR);
CheckCurrentScreen(NetworkScreenView::kScreenId);
}
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowSkipUpdateEnroll) {
InitNetworkPortalDetector();
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
WizardController::default_controller()
->wizard_context_->enrollment_triggered_early = true;
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(
EnrollmentModeMatches(policy::EnrollmentConfig::MODE_MANUAL)))
.Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, HideImpl()).Times(0);
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
ControlFlowEnrollmentCompleted) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(
EnrollmentModeMatches(policy::EnrollmentConfig::MODE_MANUAL)))
.Times(1);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
WizardController::default_controller()->AdvanceToScreen(
EnrollmentScreenView::kScreenId);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
}
IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest,
ControlFlowWrongHWIDScreenFromLogin) {
CheckCurrentScreen(WelcomeView::kScreenId);
// Verify and clear all expectations on the mock welcome screen before setting
// new ones.
testing::Mock::VerifyAndClearExpectations(mock_welcome_screen_);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
LoginDisplayHost::default_host()->StartSignInScreen();
EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
EXPECT_CALL(*mock_wrong_hwid_screen_, ShowImpl()).Times(1);
WizardController::default_controller()->AdvanceToScreen(
WrongHWIDScreenView::kScreenId);
CheckCurrentScreen(WrongHWIDScreenView::kScreenId);
// Verify and clear all expectations on the mock wrong hwid screen before
// setting new ones.
testing::Mock::VerifyAndClearExpectations(mock_wrong_hwid_screen_);
// After warning is skipped, user returns to sign-in screen.
// And this destroys WizardController.
EXPECT_CALL(*mock_wrong_hwid_screen_, HideImpl()).Times(1);
GetWrongHWIDScreen()->OnExit();
EXPECT_FALSE(ExistingUserController::current_controller() == nullptr);
}
// This parameterized test class extends WizardControllerFlowTest to verify how
// WizardController behaves if it does not find or fails to apply an update
// after the OOBE is marked complete.
class WizardControllerUpdateAfterCompletedOobeTest
: public WizardControllerFlowTest,
public testing::WithParamInterface<UpdateScreen::Result>,
public LocalStateMixin::Delegate {
public:
WizardControllerUpdateAfterCompletedOobeTest(
const WizardControllerUpdateAfterCompletedOobeTest&) = delete;
WizardControllerUpdateAfterCompletedOobeTest& operator=(
const WizardControllerUpdateAfterCompletedOobeTest&) = delete;
protected:
WizardControllerUpdateAfterCompletedOobeTest() = default;
// LocalStateMixin::Delegate:
void SetUpLocalState() override {
StartupUtils::MarkOobeCompleted(); // Pretend OOBE was complete.
}
private:
LocalStateMixin local_state_mixin_{&mixin_host_, this};
};
// This test verifies that if WizardController reports any result after the
// OOBE is marked complete, it allows the user to proceed to log in.
IN_PROC_BROWSER_TEST_P(WizardControllerUpdateAfterCompletedOobeTest,
ControlFlowErrorUpdate) {
CheckCurrentScreen(WelcomeView::kScreenId);
// Verify and clear all expectations on the mock welcome screen before setting
// new ones.
testing::Mock::VerifyAndClearExpectations(mock_welcome_screen_);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
// Verify and clear all expectations on the mock network screen before setting
// new ones.
testing::Mock::VerifyAndClearExpectations(mock_network_screen_);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
testing::Mock::VerifyAndClearExpectations(mock_update_screen_);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_update_screen_->RunExit(GetParam());
CheckCurrentScreen(UserCreationView::kScreenId);
testing::Mock::VerifyAndClearExpectations(mock_auto_enrollment_check_screen_);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_NE(nullptr, ExistingUserController::current_controller());
}
INSTANTIATE_TEST_SUITE_P(
All,
WizardControllerUpdateAfterCompletedOobeTest,
testing::Values(UpdateScreen::Result::UPDATE_NOT_REQUIRED,
UpdateScreen::Result::UPDATE_ERROR));
class WizardControllerDeviceStateTest : public WizardControllerFlowTest {
public:
WizardControllerDeviceStateTest(const WizardControllerDeviceStateTest&) =
delete;
WizardControllerDeviceStateTest& operator=(
const WizardControllerDeviceStateTest&) = delete;
protected:
WizardControllerDeviceStateTest() {
fake_statistics_provider_.SetMachineStatistic(system::kSerialNumberKey,
"test");
fake_statistics_provider_.SetMachineStatistic(system::kActivateDateKey,
"2000-01");
fake_statistics_provider_.SetVpdStatus(
system::StatisticsProvider::VpdStatus::kValid);
// Make all requests to DMServer fail with net::ERR_CONNECTION_REFUSED.
test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
if (request.url.spec().starts_with(kDMServerURLPrefix)) {
test_url_loader_factory_.AddResponse(
request.url, network::mojom::URLResponseHead::New(),
std::string(),
network::URLLoaderCompletionStatus(
net::ERR_CONNECTION_REFUSED));
}
}));
}
static policy::AutoEnrollmentController* auto_enrollment_controller() {
return WizardController::default_controller()
->GetAutoEnrollmentController();
}
static void WaitForAutoEnrollmentState(policy::AutoEnrollmentState state) {
base::RunLoop loop;
base::CallbackListSubscription progress_subscription =
auto_enrollment_controller()->RegisterProgressCallback(
base::BindRepeating(&QuitLoopOnAutoEnrollmentProgress, state,
&loop));
loop.Run();
}
// WizardControllerFlowTest:
void SetUpOnMainThread() override {
WizardControllerFlowTest::SetUpOnMainThread();
histogram_tester_ = std::make_unique<base::HistogramTester>();
// Initialize the FakeShillManagerClient. This does not happen
// automatically because of the `DBusThreadManager::Initialize`
// call in `SetUpInProcessBrowserTestFixture`. See https://crbug.com/847422.
// TODO(pmarko): Find a way for FakeShillManagerClient to be initialized
// automatically (https://crbug.com/847422).
ShillManagerClient::Get()->GetTestInterface()->SetupDefaultEnvironment();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerFlowTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableForcedReEnrollment,
policy::AutoEnrollmentTypeChecker::kForcedReEnrollmentAlways);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnrollmentInitialModulus, "1");
command_line->AppendSwitchASCII(switches::kEnterpriseEnrollmentModulusLimit,
"2");
}
system::ScopedFakeStatisticsProvider fake_statistics_provider_;
base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
private:
DeviceStateMixin device_state_{&mixin_host_,
DeviceStateMixin::State::BEFORE_OOBE};
std::unique_ptr<base::HistogramTester> histogram_tester_;
};
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateTest,
AutoEnrollmentControllerStartedAfterNetworkScreen) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
content::RunAllTasksUntilIdle();
// Verify that the state fetch has started or already completed.
EXPECT_TRUE(auto_enrollment_controller()->IsInProgress() ||
auto_enrollment_controller()->state().has_value());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateTest,
ControlFlowNoForcedReEnrollmentOnFirstBoot) {
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
EXPECT_NE(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_EQ(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
EXPECT_EQ(1,
FakeInstallAttributesClient::Get()
->remove_firmware_management_parameters_from_tpm_call_count());
EXPECT_EQ(1, FakeSessionManagerClient::Get()
->clear_forced_re_enrollment_vpd_call_count());
}
class WizardControllerDeviceLegacyTest
: public WizardControllerDeviceStateTest {
public:
WizardControllerDeviceLegacyTest(
const WizardControllerDeviceLegacyTest&) = delete;
WizardControllerDeviceLegacyTest& operator=(
const WizardControllerDeviceLegacyTest&) = delete;
protected:
WizardControllerDeviceLegacyTest() = default;
~WizardControllerDeviceLegacyTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerDeviceStateTest::SetUpCommandLine(command_line);
// Explicitly test legacy state determination flow.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationNever);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceLegacyTest,
ServerAdvertisedReEnrollment) {
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentRequested));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
base::RunLoop().RunUntilIdle();
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
mock_auto_enrollment_check_screen_->ExitScreen();
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::BACK);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
// TODO(crbug.com/41429868) Flaky time outs on Linux ChromiumOS ASan LSan bot.
#if defined(ADDRESS_SANITIZER)
#define MAYBE_ControlFlowDeviceDisabled DISABLED_ControlFlowDeviceDisabled
#else
#define MAYBE_ControlFlowDeviceDisabled ControlFlowDeviceDisabled
#endif
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceLegacyTest,
MAYBE_ControlFlowDeviceDisabled) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
mock_auto_enrollment_check_screen_->RealShow();
// Wait for auto-enrollment controller to encounter the connection error.
WaitForAutoEnrollmentState(kAutoEnrollmentConnectionError);
// The error screen shows up if device state could not be retrieved.
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
base::Value::Dict device_state;
device_state.Set(policy::kDeviceStateMode,
base::Value(policy::kDeviceStateModeDisabled));
device_state.Set(policy::kDeviceStateDisabledMessage,
base::Value(kDisabledMessage));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*device_disabled_screen_view_,
Show(Field(&DeviceDisabledScreenView::Params::message,
Eq(kDisabledMessage))))
.Times(1);
mock_auto_enrollment_check_screen_->ExitScreen();
base::RunLoop().RunUntilIdle();
ResetAutoEnrollmentCheckScreen();
// Make sure the device disabled screen is shown.
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
EXPECT_EQ(0,
FakeInstallAttributesClient::Get()
->remove_firmware_management_parameters_from_tpm_call_count());
EXPECT_EQ(0, FakeSessionManagerClient::Get()
->clear_forced_re_enrollment_vpd_call_count());
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
}
// Allows testing different behavior if forced re-enrollment is performed but
// not explicitly required (instantiated with `false`) vs. if forced
// re-enrollment is explicitly required (instantiated with `true`).
class WizardControllerDeviceStateExplicitRequirementTest
: public WizardControllerDeviceStateTest,
public testing::WithParamInterface<bool /* fre_explicitly_required */> {
public:
WizardControllerDeviceStateExplicitRequirementTest(
const WizardControllerDeviceStateExplicitRequirementTest&) = delete;
WizardControllerDeviceStateExplicitRequirementTest& operator=(
const WizardControllerDeviceStateExplicitRequirementTest&) = delete;
protected:
WizardControllerDeviceStateExplicitRequirementTest() {
if (IsFREExplicitlyRequired()) {
fake_statistics_provider_.SetMachineStatistic(system::kCheckEnrollmentKey,
"1");
}
}
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerDeviceStateTest::SetUpCommandLine(command_line);
// Explicitly test legacy state determination flow.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationNever);
}
// Returns true if forced re-enrollment was explicitly required (which
// corresponds to the check_enrollment VPD value being set to "1").
bool IsFREExplicitlyRequired() { return GetParam(); }
};
// Test the control flow for Forced Re-Enrollment. First, a connection error
// occurs, leading to a network error screen. On the network error screen, the
// test verifies that the user may enter a guest session if FRE was not
// explicitly required, and that the user may not enter a guest session if FRE
// was explicitly required. Then, a retry is performed and FRE indicates that
// the device should be enrolled.
IN_PROC_BROWSER_TEST_P(WizardControllerDeviceStateExplicitRequirementTest,
ControlFlowForcedReEnrollment) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
mock_auto_enrollment_check_screen_->RealShow();
// Wait for auto-enrollment controller to encounter the connection error.
WaitForAutoEnrollmentState(kAutoEnrollmentConnectionError);
// The error screen shows up if there's no auto-enrollment decision.
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
if (IsFREExplicitlyRequired()) {
// Check that guest sign-in is not allowed on the network error screen
// (because the check_enrollment VPD key was set to "1", making FRE
// explicitly required).
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
} else {
// Check that guest sign-in is allowed if FRE was not explicitly required.
test::OobeJS().ExpectVisiblePath(kGuestSessionLink);
}
EXPECT_EQ(0,
FakeInstallAttributesClient::Get()
->remove_firmware_management_parameters_from_tpm_call_count());
EXPECT_EQ(0, FakeSessionManagerClient::Get()
->clear_forced_re_enrollment_vpd_call_count());
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
mock_auto_enrollment_check_screen_->ExitScreen();
ResetAutoEnrollmentCheckScreen();
// Make sure enterprise enrollment page shows up.
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
// Tests that a server error occurs during a check for Forced Re-Enrollment.
// When Forced Re-Enrollment is not explicitly required (there is no
// "check_enrollment" VPD key), the expectation is that the server error is
// treated as "don't force enrollment".
// When Forced Re-Enrollment is explicitly required (the "check_enrollment" VPD
// key is set to "1"), the expectation is that a network error screen shows up
// (from which it's not possible to enter a Guest session).
IN_PROC_BROWSER_TEST_P(WizardControllerDeviceStateExplicitRequirementTest,
ControlFlowForcedReEnrollmentServerError) {
ScopedFakeAutoEnrollmentClientFactory fake_auto_enrollment_client_factory(
auto_enrollment_controller());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
policy::FakeAutoEnrollmentClient* fake_auto_enrollment_client =
fake_auto_enrollment_client_factory.WaitAutoEnrollmentClientCreated();
if (IsFREExplicitlyRequired()) {
// Expect that the auto enrollment screen will be hidden, because OOBE is
// switching to the error screen.
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
// Make AutoEnrollmentClient notify the controller that a server error
// occurred.
fake_auto_enrollment_client->SetState(kAutoEnrollmentServerError);
base::RunLoop().RunUntilIdle();
// The error screen shows up.
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
// Check that guest sign-in is not allowed on the network error screen
// (because the check_enrollment VPD key was set to "1", making FRE
// explicitly required).
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
fake_auto_enrollment_client->SetState(
policy::AutoEnrollmentResult::kEnrollment);
mock_auto_enrollment_check_screen_->ExitScreen();
ResetAutoEnrollmentCheckScreen();
// Make sure enterprise enrollment page shows up.
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
EXPECT_EQ(
0, FakeInstallAttributesClient::Get()
->remove_firmware_management_parameters_from_tpm_call_count());
EXPECT_EQ(0, FakeSessionManagerClient::Get()
->clear_forced_re_enrollment_vpd_call_count());
} else {
// Make AutoEnrollmentClient notify the controller that a server error
// occurred.
fake_auto_enrollment_client->SetState(kAutoEnrollmentServerError);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
// Don't expect that the auto enrollment screen will be hidden, because
// OOBE is exited from the auto enrollment screen. Instead only expect
// that the sign-in screen is reached.
OobeScreenWaiter(GetFirstSigninScreen()).Wait();
EXPECT_EQ(
0, FakeInstallAttributesClient::Get()
->remove_firmware_management_parameters_from_tpm_call_count());
EXPECT_EQ(0, FakeSessionManagerClient::Get()
->clear_forced_re_enrollment_vpd_call_count());
}
}
INSTANTIATE_TEST_SUITE_P(All,
WizardControllerDeviceStateExplicitRequirementTest,
testing::Values(false, true));
class WizardControllerUnifiedEnrollmentTest
: public WizardControllerDeviceStateTest {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerDeviceStateTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationAlways);
}
void ProgressUntilAutoEnrollmentCheckScreen() {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl());
EXPECT_CALL(*mock_network_screen_, ShowImpl());
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl());
EXPECT_CALL(*mock_update_screen_, ShowImpl());
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl());
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl());
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
}
};
// Tests that when EnrollmentStateFetcher reports kNoEnrollment, we skip
// enrollment screen and set state correctly.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, NoEnrollment) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
fetcher_factory.ReportEnrollmentState(
policy::AutoEnrollmentResult::kNoEnrollment);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, HideImpl()).Times(0);
EXPECT_EQ(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::
kForcedReEnrollmentExplicitlyRequired,
auto_enrollment_controller()->auto_enrollment_check_type());
}
// Tests that when EnrollmentStateFetcher reports state keys retrieval error, we
// show an error on enrollment check screen and that it is not possible to enter
// guest mode.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest,
BlockedByCommunicationErrorOnStateKeysRetrieval) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
fetcher_factory.ReportEnrollmentState(kAutoEnrollmentStateKeysRetrievalError);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
}
// Tests that when EnrollmentStateFetcher reports kServerError, we show an error
// on enrollment check screen and that it is not possible to enter guest mode.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, ServerError) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
fetcher_factory.ReportEnrollmentState(kAutoEnrollmentServerError);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
}
// Tests that when EnrollmentStateFetcher reports kConnectionError, we show an
// error on enrollment check screen and that it is not possible to enter guest
// mode (like in FRE).
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, ConnectionError) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
fetcher_factory.ReportEnrollmentState(kAutoEnrollmentConnectionError);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
}
// Tests that when EnrollmentStateFetcher reports kEnrollment and configures
// device state mode as FRE, we shown enrollment screen.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, Enrollment) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl());
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl());
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
fetcher_factory.ReportEnrollmentState(
policy::AutoEnrollmentResult::kEnrollment);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
}
// Tests that when EnrollmentStateFetcher reports kDisabled and configures
// corresponding device state mode, we show device disabled screen.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, Disabled) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl());
EXPECT_CALL(*device_disabled_screen_view_,
Show(Field(&DeviceDisabledScreenView::Params::message,
Eq(kDisabledMessage))));
base::Value::Dict device_state;
device_state.Set(policy::kDeviceStateMode,
base::Value(policy::kDeviceStateModeDisabled));
device_state.Set(policy::kDeviceStateDisabledMessage,
base::Value(kDisabledMessage));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
fetcher_factory.ReportEnrollmentState(
policy::AutoEnrollmentResult::kDisabled);
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
}
// Tests that when EnrollmentStateFetcher reports kDisabled and configures
// corresponding device state mode, we show device disabled screen after
// attempting to enter demo mode.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest,
DisabledDemoMode) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_welcome_screen_, HideImpl());
EXPECT_CALL(*mock_network_screen_, ShowImpl());
WizardController::default_controller()->StartDemoModeSetup();
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_network_screen_, HideImpl());
EXPECT_CALL(*mock_demo_preferences_screen_, ShowImpl());
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_preferences_screen_, HideImpl());
EXPECT_CALL(*mock_update_screen_, ShowImpl());
mock_demo_preferences_screen_->ExitScreen(
DemoPreferencesScreen::Result::COMPLETED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl());
EXPECT_CALL(*mock_consolidated_consent_screen_, ShowImpl());
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(ConsolidatedConsentScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_consolidated_consent_screen_, HideImpl());
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl());
mock_consolidated_consent_screen_->ExitScreen(
ConsolidatedConsentScreen::Result::ACCEPTED_DEMO_ONLINE);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
mock_auto_enrollment_check_screen_->RealShow();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
base::Value::Dict device_state;
device_state.Set(policy::kDeviceStateMode,
base::Value(policy::kDeviceStateModeDisabled));
device_state.Set(policy::kDeviceStateDisabledMessage,
base::Value(kDisabledMessage));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl());
EXPECT_CALL(*device_disabled_screen_view_,
Show(Field(&DeviceDisabledScreenView::Params::message,
Eq(kDisabledMessage))));
fetcher_factory.ReportEnrollmentState(
policy::AutoEnrollmentResult::kDisabled);
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
}
// Tests that when EnrollmentStateFetcher times out, we set state correctly,
// show an error on enrollment check screen and that it is not possible to enter
// guest mode (like in FRE).
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, Timeout) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
auto_enrollment_controller()->SafeguardTimerForTesting().FireNow();
// Ensure that we show an error on enrollment check screen and that it is not
// possible to enter guest mode (like in FRE).
EXPECT_EQ(
auto_enrollment_controller()->state(),
ToAutoEnrollmentState(policy::AutoEnrollmentSafeguardTimeoutError{}));
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
test::OobeJS().ExpectHiddenPath(kGuestSessionLink);
histogram_tester()->ExpectBucketCount(
"Enterprise.AutoEnrollmentControllerTimeout", 3 /*kTimeoutUnified*/, 1);
}
// Tests that AutoEnrollmentController does not create another
// EnrollmentStateFetcher while previous one is still running, but also that it
// does create one when previous has completed and reported a state.
IN_PROC_BROWSER_TEST_F(WizardControllerUnifiedEnrollmentTest, OneFetchAtATime) {
ScopedEnrollmentStateFetcherFactory fetcher_factory(
auto_enrollment_controller());
ProgressUntilAutoEnrollmentCheckScreen();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
// This should determine that the enrollment state is already being fetched
// and skip creating a new EnrollmentStateFetcher. Otherwise, it would fail an
// expectation in fetcher_factory allowing only one EnrollmentStateFetcher to
// be created.
auto_enrollment_controller()->Start();
// Simulate connection error, reset factory and attempt a retry.
fetcher_factory.ReportEnrollmentState(kAutoEnrollmentConnectionError);
fetcher_factory.Reset();
auto_enrollment_controller()->Retry();
fetcher_factory.WaitUntilEnrollmentStateFetcherCreated();
}
class WizardControllerDeviceStateWithInitialEnrollmentTest
: public WizardControllerDeviceStateTest {
public:
WizardControllerDeviceStateWithInitialEnrollmentTest(
const WizardControllerDeviceStateWithInitialEnrollmentTest&) = delete;
WizardControllerDeviceStateWithInitialEnrollmentTest& operator=(
const WizardControllerDeviceStateWithInitialEnrollmentTest&) = delete;
protected:
WizardControllerDeviceStateWithInitialEnrollmentTest() {
fake_statistics_provider_.SetMachineStatistic(system::kSerialNumberKey,
"test");
fake_statistics_provider_.SetMachineStatistic(system::kRlzBrandCodeKey,
"AABC");
}
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerDeviceStateTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableInitialEnrollment,
policy::AutoEnrollmentTypeChecker::kInitialEnrollmentAlways);
// Explicitly test legacy state determination flow.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationNever);
}
// Test initial enrollment. This method is shared by the tests for initial
// enrollment for a device that is new or in consumer mode. |check_fre|
// specifies if forced re-enrollment check is needed.
void DoInitialEnrollment(bool check_fre) {
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(-15 /* days_offset */));
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
if (check_fre) {
// Wait for auto-enrollment controller to encounter the connection error.
WaitForAutoEnrollmentState(
ToAutoEnrollmentState(policy::AutoEnrollmentDMServerError{
.dm_error = policy::DM_STATUS_REQUEST_FAILED,
.network_error = net::ERR_CONNECTION_REFUSED}));
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
}
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
if (check_fre) {
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
} else {
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
}
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
if (check_fre) {
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
mock_auto_enrollment_check_screen_->RealShow();
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
mock_auto_enrollment_check_screen_->ExitScreen();
} else {
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
}
// The error screen shows up if there's no auto-enrollment decision.
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
if (check_fre) {
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
}
ResetAutoEnrollmentCheckScreen();
// Make sure enterprise enrollment page shows up.
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
SystemClockClient::TestInterface* system_clock_client() {
return SystemClockClient::Get()->GetTestInterface();
}
};
// Tests that a device that is brand new properly does initial enrollment.
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowInitialEnrollment) {
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
DoInitialEnrollment(/*check_fre=*/true);
}
// Tests that a device that is in consumer mode can do another initial
// enrollment.
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowSecondaryInitialEnrollment) {
// Mark the device has being in consumer mode.
fake_statistics_provider_.SetMachineStatistic(system::kCheckEnrollmentKey,
"0");
// TODO(igorcov): Change to /*check_fre=*/false when b/238592446 is fixed.
// At that point we might need to add
// WizardController::default_controller()
// ->GetAutoEnrollmentControllerForTesting()
// ->SetRlweClientFactoryForTesting(
// base::BindRepeating(&policy::psm::FakeRlweClient::Create));
DoInitialEnrollment(/*check_fre=*/true);
}
// Tests that a server error occurs during the Initial Enrollment check. The
// expectation is that a network error screen shows up (from which it's possible
// to enter a Guest session).
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowInitialEnrollmentServerError) {
ScopedFakeAutoEnrollmentClientFactory fake_auto_enrollment_client_factory(
auto_enrollment_controller());
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(-15 /* days_offset */));
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
policy::FakeAutoEnrollmentClient* fake_auto_enrollment_client =
fake_auto_enrollment_client_factory.WaitAutoEnrollmentClientCreated();
// Expect that the auto enrollment screen will be hidden, because OOBE is
// switching to the error screen.
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
// Make AutoEnrollmentClient notify the controller that a server error
// occurred.
fake_auto_enrollment_client->SetState(kAutoEnrollmentServerError);
base::RunLoop().RunUntilIdle();
// The error screen shows up if there's no auto-enrollment decision.
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
// Check that guest sign-in is allowed on the network error screen for initial
// enrollment.
test::OobeJS().ExpectVisiblePath(kGuestSessionLink);
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
fake_auto_enrollment_client->SetState(
policy::AutoEnrollmentResult::kEnrollment);
mock_auto_enrollment_check_screen_->ExitScreen();
ResetAutoEnrollmentCheckScreen();
// Make sure enterprise enrollment page shows up.
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowNoInitialEnrollmentDuringEmbargoPeriod) {
system_clock_client()->SetNetworkSynchronized(true);
system_clock_client()->NotifyObserversSystemClockUpdated();
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(1 /* days_offset */));
EXPECT_NE(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(UserCreationView::kScreenId);
EXPECT_EQ(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowWaitSystemClockSyncThenEmbargoPeriod) {
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(1 /* days_offset */));
EXPECT_NE(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::
kUnknownDueToMissingSystemClockSync,
auto_enrollment_controller()->auto_enrollment_check_type());
system_clock_client()->SetNetworkSynchronized(true);
system_clock_client()->NotifyObserversSystemClockUpdated();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::kNone,
auto_enrollment_controller()->auto_enrollment_check_type());
EXPECT_EQ(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowWaitSystemClockSyncTimeout) {
auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
base::TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner);
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(1 /* days_offset */));
EXPECT_NE(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
task_runner->RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::
kUnknownDueToMissingSystemClockSync,
auto_enrollment_controller()->auto_enrollment_check_type());
// The timeout is 45 seconds, see `auto_enrollment_controller.cc`.
// Fast-forward by a bit more than that.
task_runner->FastForwardBy(base::Seconds(45 + 1));
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::
kUnknownDueToMissingSystemClockSync,
auto_enrollment_controller()->auto_enrollment_check_type());
EXPECT_EQ(
auto_enrollment_controller()->state(),
ToAutoEnrollmentState(policy::AutoEnrollmentSystemClockSyncError{}));
}
IN_PROC_BROWSER_TEST_F(WizardControllerDeviceStateWithInitialEnrollmentTest,
ControlFlowWaitSystemClockSyncThenInitialEnrollment) {
ScopedFakeAutoEnrollmentClientFactory fake_auto_enrollment_client_factory(
auto_enrollment_controller());
fake_statistics_provider_.ClearMachineStatistic(system::kActivateDateKey);
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(1 /* days_offset */));
EXPECT_NE(policy::AutoEnrollmentResult::kNoEnrollment,
auto_enrollment_controller()->state());
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
mock_auto_enrollment_check_screen_->RealShow();
EXPECT_EQ(policy::AutoEnrollmentTypeChecker::CheckType::
kUnknownDueToMissingSystemClockSync,
auto_enrollment_controller()->auto_enrollment_check_type());
// Simulate that the clock moved forward, passing the embargo period, by
// moving the embargo period back in time.
fake_statistics_provider_.SetMachineStatistic(
system::kRlzEmbargoEndDateKey,
GenerateEmbargoEndDate(-1 /* days_offset */));
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateRestoreModeReEnrollmentEnforced));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
system_clock_client()->SetNetworkSynchronized(true);
system_clock_client()->NotifyObserversSystemClockUpdated();
policy::FakeAutoEnrollmentClient* fake_auto_enrollment_client =
fake_auto_enrollment_client_factory.WaitAutoEnrollmentClientCreated();
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_SERVER_FORCED)))
.Times(1);
mock_auto_enrollment_check_screen_->ExitScreen();
ResetAutoEnrollmentCheckScreen();
fake_auto_enrollment_client->SetState(
policy::AutoEnrollmentResult::kEnrollment);
// Make sure enterprise enrollment page shows up.
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
class WizardControllerScreenPriorityOOBETest : public OobeBaseTest {
protected:
WizardControllerScreenPriorityOOBETest() = default;
~WizardControllerScreenPriorityOOBETest() override = default;
void CheckCurrentScreen(OobeScreenId screen) {
EXPECT_EQ(WizardController::default_controller()->GetScreen(screen),
WizardController::default_controller()->current_screen());
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerScreenPriorityOOBETest,
DefaultPriorityTest) {
ASSERT_TRUE(WizardController::default_controller() != nullptr);
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
CheckCurrentScreen(WelcomeView::kScreenId);
// Showing network screen should pass it has default priority which is same as
// welcome screen.
WizardController::default_controller()->AdvanceToScreen(
NetworkScreenView::kScreenId);
CheckCurrentScreen(NetworkScreenView::kScreenId);
// Showing update screen should pass it has default priority which is same as
// network screen.
WizardController::default_controller()->AdvanceToScreen(
UpdateView::kScreenId);
CheckCurrentScreen(UpdateView::kScreenId);
}
class WizardControllerScreenPriorityTest : public LoginManagerTest,
public LocalStateMixin::Delegate {
protected:
WizardControllerScreenPriorityTest() {
login_manager_mixin_.AppendRegularUsers(1);
}
~WizardControllerScreenPriorityTest() override = default;
void CheckCurrentScreen(OobeScreenId screen) {
EXPECT_EQ(WizardController::default_controller()->GetScreen(screen),
WizardController::default_controller()->current_screen());
}
// LocalStateMixin::Delegate:
void SetUpLocalState() override {
// Set pref to show reset screen on startup.
g_browser_process->local_state()->SetBoolean(prefs::kFactoryResetRequested,
true);
}
private:
LoginManagerMixin login_manager_mixin_{&mixin_host_};
LocalStateMixin local_state_mixin_{&mixin_host_, this};
};
IN_PROC_BROWSER_TEST_F(WizardControllerScreenPriorityTest, CanNavigateToTest) {
WizardController* const wizard_controller =
WizardController::default_controller();
ASSERT_TRUE(wizard_controller != nullptr);
EXPECT_EQ(1, LoginScreenTestApi::GetUsersCount());
// Check reset screen is visible on startup.
OobeScreenWaiter(ResetView::kScreenId).Wait();
EXPECT_TRUE(LoginScreenTestApi::IsOobeDialogVisible());
// Showing update required screen should fail due to lower priority than reset
// screen.
LoginDisplayHost::default_host()->StartWizard(UpdateRequiredView::kScreenId);
CheckCurrentScreen(ResetView::kScreenId);
// Wizard controller should not be recreated.
EXPECT_EQ(wizard_controller, WizardController::default_controller());
// Showing device disabled screen is allowed due to higher priority than reset
// screen.
LoginDisplayHost::default_host()->StartWizard(
DeviceDisabledScreenView::kScreenId);
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
// Wizard controller should not be recreated.
EXPECT_EQ(wizard_controller, WizardController::default_controller());
// Showing update required screen should fail due to lower priority than
// device disabled screen.
LoginDisplayHost::default_host()->StartWizard(UpdateRequiredView::kScreenId);
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
EXPECT_EQ(wizard_controller, WizardController::default_controller());
}
class WizardControllerBrokenLocalStateTest : public WizardControllerTest {
public:
WizardControllerBrokenLocalStateTest(
const WizardControllerBrokenLocalStateTest&) = delete;
WizardControllerBrokenLocalStateTest& operator=(
const WizardControllerBrokenLocalStateTest&) = delete;
protected:
WizardControllerBrokenLocalStateTest() = default;
~WizardControllerBrokenLocalStateTest() override = default;
// WizardControllerTest:
void SetUpInProcessBrowserTestFixture() override {
WizardControllerTest::SetUpInProcessBrowserTestFixture();
PrefServiceFactory factory;
factory.set_user_prefs(base::MakeRefCounted<PrefStoreStub>());
local_state_ = factory.Create(new PrefRegistrySimple());
WizardController::set_local_state_for_testing(local_state_.get());
}
private:
std::unique_ptr<PrefService> local_state_;
};
IN_PROC_BROWSER_TEST_F(WizardControllerBrokenLocalStateTest,
LocalStateCorrupted) {
// Checks that after wizard controller initialization local error screen
// is displayed.
ASSERT_EQ(WizardController::default_controller()->GetScreen(
LocalStateErrorScreenView::kScreenId),
WizardController::default_controller()->current_screen());
OobeScreenWaiter(LocalStateErrorScreenView::kScreenId).Wait();
// Checks visibility of the powerwash button.
test::OobeJS().ExpectVisiblePath({"local-state-error", "powerwashButton"});
// Emulates user click on the "Restart and Powerwash" button.
ASSERT_EQ(0, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
test::OobeJS().TapOnPath({"local-state-error", "powerwashButton"});
ASSERT_EQ(1, FakeSessionManagerClient::Get()->start_device_wipe_call_count());
}
class WizardControllerProxyAuthOnSigninTest : public OobeBaseTest {
public:
WizardControllerProxyAuthOnSigninTest(
const WizardControllerProxyAuthOnSigninTest&) = delete;
WizardControllerProxyAuthOnSigninTest& operator=(
const WizardControllerProxyAuthOnSigninTest&) = delete;
protected:
WizardControllerProxyAuthOnSigninTest()
: proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY,
base::FilePath()) {}
~WizardControllerProxyAuthOnSigninTest() override = default;
// WizardControllerTest:
void SetUp() override {
ASSERT_TRUE(proxy_server_.Start());
OobeBaseTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
OobeBaseTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(::switches::kProxyServer,
proxy_server_.host_port_pair().ToString());
}
net::SpawnedTestServer& proxy_server() { return proxy_server_; }
private:
DeviceStateMixin device_state_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
net::SpawnedTestServer proxy_server_;
};
// TODO(crbug.com/1286218): Flakes on CrOS.
// TODO(crbug.com/41486698): Re-enable this test
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_ProxyAuthDialogOnSigninScreen \
DISABLED_ProxyAuthDialogOnSigninScreen
#else
#define MAYBE_ProxyAuthDialogOnSigninScreen ProxyAuthDialogOnSigninScreen
#endif
IN_PROC_BROWSER_TEST_F(WizardControllerProxyAuthOnSigninTest,
MAYBE_ProxyAuthDialogOnSigninScreen) {
OobeScreenWaiter(GaiaView::kScreenId).Wait();
ASSERT_TRUE(base::test::RunUntil(
[]() { return HttpAuthDialog::GetAllDialogsForTest().size() == 1; }));
}
class WizardControllerKioskFlowTest : public WizardControllerFlowTest {
public:
WizardControllerKioskFlowTest(const WizardControllerKioskFlowTest&) = delete;
WizardControllerKioskFlowTest& operator=(
const WizardControllerKioskFlowTest&) = delete;
protected:
WizardControllerKioskFlowTest() = default;
// WizardControllerFlowTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerFlowTest::SetUpCommandLine(command_line);
base::FilePath test_data_dir;
ASSERT_TRUE(chromeos::test_utils::GetTestDataPath(
"app_mode", "kiosk_manifest", &test_data_dir));
command_line->AppendSwitchPath(
switches::kAppOemManifestFile,
test_data_dir.AppendASCII("kiosk_manifest.json"));
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerKioskFlowTest,
ControlFlowKioskForcedEnrollment) {
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_LOCAL_FORCED)))
.Times(1);
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
// Make sure enterprise enrollment page shows up right after update screen.
mock_enrollment_screen_->ExitScreen(EnrollmentScreen::Result::COMPLETED);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
}
IN_PROC_BROWSER_TEST_F(WizardControllerKioskFlowTest,
ControlFlowEnrollmentBackForced) {
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(EnrollmentModeMatches(
policy::EnrollmentConfig::MODE_LOCAL_FORCED)))
.Times(2);
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kNext);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
// Make sure enterprise enrollment page shows up right after update screen.
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_enrollment_screen_, HideImpl()).Times(0);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
mock_enrollment_screen_->ExitScreen(
EnrollmentScreen::Result::BACK_TO_AUTO_ENROLLMENT_CHECK);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
}
class WizardControllerEnableAdbSideloadingTest
: public WizardControllerFlowTest {
public:
WizardControllerEnableAdbSideloadingTest(
const WizardControllerEnableAdbSideloadingTest&) = delete;
WizardControllerEnableAdbSideloadingTest& operator=(
const WizardControllerEnableAdbSideloadingTest&) = delete;
protected:
WizardControllerEnableAdbSideloadingTest() = default;
template <class T>
void SkipToScreen(OobeScreenId screen, T* screen_mock) {
EXPECT_CALL(*screen_mock, ShowImpl()).Times(1);
auto* const wizard_controller = WizardController::default_controller();
wizard_controller->AdvanceToScreen(screen);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerEnableAdbSideloadingTest,
ShowAndEnableSideloading) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
SkipToScreen(EnableAdbSideloadingScreenView::kScreenId,
mock_enable_adb_sideloading_screen_.get());
CheckCurrentScreen(EnableAdbSideloadingScreenView::kScreenId);
EXPECT_CALL(*mock_enable_adb_sideloading_screen_,
OnUserAction(ElementsAre("enable-pressed")))
.Times(1);
test::OobeJS().ClickOnPath(
{"adb-sideloading", "enable-adb-sideloading-ok-button"});
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(EnableAdbSideloadingScreenView::kScreenId);
EXPECT_CALL(*mock_enable_adb_sideloading_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_enable_adb_sideloading_screen_->ExitScreen();
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(WelcomeView::kScreenId);
}
IN_PROC_BROWSER_TEST_F(WizardControllerEnableAdbSideloadingTest,
ShowAndDoNotEnableSideloading) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
SkipToScreen(EnableAdbSideloadingScreenView::kScreenId,
mock_enable_adb_sideloading_screen_.get());
CheckCurrentScreen(EnableAdbSideloadingScreenView::kScreenId);
EXPECT_CALL(*mock_enable_adb_sideloading_screen_,
OnUserAction(ElementsAre("cancel-pressed")))
.Times(1);
test::OobeJS().ClickOnPath(
{"adb-sideloading", "enable-adb-sideloading-cancel-button"});
base::RunLoop().RunUntilIdle();
EXPECT_CALL(*mock_enable_adb_sideloading_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_enable_adb_sideloading_screen_->ExitScreen();
// Let update screen smooth time process (time = 0ms).
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(WelcomeView::kScreenId);
}
class WizardControllerEnableDebuggingTest : public WizardControllerFlowTest {
public:
WizardControllerEnableDebuggingTest(
const WizardControllerEnableDebuggingTest&) = delete;
WizardControllerEnableDebuggingTest& operator=(
const WizardControllerEnableDebuggingTest&) = delete;
protected:
WizardControllerEnableDebuggingTest() = default;
// MixinBasedInProcessBrowserTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerFlowTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(chromeos::switches::kSystemDevMode);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerEnableDebuggingTest,
ShowAndCancelEnableDebugging) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_enable_debugging_screen_, ShowImpl()).Times(1);
mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::kEnableDebugging);
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(EnableDebuggingScreenView::kScreenId);
EXPECT_CALL(*mock_enable_debugging_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_enable_debugging_screen_->ExitScreen();
// Let update screen smooth time process (time = 0ms).
content::RunAllPendingInMessageLoop();
CheckCurrentScreen(WelcomeView::kScreenId);
}
class WizardControllerDemoSetupTest : public WizardControllerFlowTest {
public:
WizardControllerDemoSetupTest(const WizardControllerDemoSetupTest&) = delete;
WizardControllerDemoSetupTest& operator=(
const WizardControllerDemoSetupTest&) = delete;
protected:
WizardControllerDemoSetupTest() = default;
~WizardControllerDemoSetupTest() override = default;
// MixinBasedInProcessBrowserTest:
void SetUpOnMainThread() override {
WizardControllerFlowTest::SetUpOnMainThread();
testing::Mock::VerifyAndClearExpectations(mock_welcome_screen_);
}
template <class T>
void SkipToScreen(OobeScreenId screen, T* screen_mock) {
EXPECT_CALL(*screen_mock, ShowImpl()).Times(1);
auto* const wizard_controller = WizardController::default_controller();
wizard_controller->SimulateDemoModeSetupForTesting();
wizard_controller->AdvanceToScreen(screen);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest,
OnlineDemoSetupFlowFinished) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
WizardController::default_controller()->StartDemoModeSetup();
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_demo_preferences_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_preferences_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_demo_preferences_screen_->ExitScreen(
DemoPreferencesScreen::Result::COMPLETED);
base::RunLoop().RunUntilIdle();
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_consolidated_consent_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
EXPECT_CALL(*mock_consolidated_consent_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_demo_setup_screen_, ShowImpl()).Times(1);
mock_consolidated_consent_screen_->ExitScreen(
ConsolidatedConsentScreen::Result::ACCEPTED_DEMO_ONLINE);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
CheckCurrentScreen(DemoSetupScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
test::LockDemoDeviceInstallAttributes();
mock_demo_setup_screen_->ExitScreen(DemoSetupScreen::Result::kCompleted);
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
EXPECT_TRUE(ExistingUserController::current_controller());
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, DemoSetupCanceled) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
WizardController::default_controller()->StartDemoModeSetup();
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_demo_preferences_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_preferences_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_demo_preferences_screen_->ExitScreen(
DemoPreferencesScreen::Result::COMPLETED);
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_consolidated_consent_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(ConsolidatedConsentScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_consolidated_consent_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(0);
EXPECT_CALL(*mock_demo_setup_screen_, ShowImpl()).Times(1);
mock_consolidated_consent_screen_->ExitScreen(
ConsolidatedConsentScreen::Result::ACCEPTED_DEMO_ONLINE);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(0);
CheckCurrentScreen(DemoSetupScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_setup_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_demo_setup_screen_->ExitScreen(DemoSetupScreen::Result::kCanceled);
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, DemoPreferencesCanceled) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
SkipToScreen(DemoPreferencesScreenView::kScreenId,
mock_demo_preferences_screen_.get());
CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_preferences_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
mock_demo_preferences_screen_->ExitScreen(
DemoPreferencesScreen::Result::CANCELED);
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::BACK);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
}
IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupTest, NetworkBackPressed) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
SkipToScreen(NetworkScreenView::kScreenId, mock_network_screen_.get());
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::BACK);
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
}
class WizardControllerDemoSetupDeviceDisabledTest
: public WizardControllerDeviceStateTest {
public:
WizardControllerDemoSetupDeviceDisabledTest(
const WizardControllerDemoSetupDeviceDisabledTest&) = delete;
WizardControllerDemoSetupDeviceDisabledTest& operator=(
const WizardControllerDemoSetupDeviceDisabledTest&) = delete;
protected:
WizardControllerDemoSetupDeviceDisabledTest() = default;
~WizardControllerDemoSetupDeviceDisabledTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerDeviceStateTest::SetUpCommandLine(command_line);
// Explicitly test legacy state determination flow.
command_line->AppendSwitchASCII(
switches::kEnterpriseEnableUnifiedStateDetermination,
policy::AutoEnrollmentTypeChecker::kUnifiedStateDeterminationNever);
}
// MixinBasedInProcessBrowserTest:
void SetUpOnMainThread() override {
WizardControllerDeviceStateTest::SetUpOnMainThread();
testing::Mock::VerifyAndClearExpectations(mock_welcome_screen_);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupDeviceDisabledTest,
OnlineDemoSetup) {
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
WizardController::default_controller()->StartDemoModeSetup();
CheckCurrentScreen(NetworkScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_demo_preferences_screen_, ShowImpl()).Times(1);
mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED);
CheckCurrentScreen(DemoPreferencesScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_demo_preferences_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(1);
mock_demo_preferences_screen_->ExitScreen(
DemoPreferencesScreen::Result::COMPLETED);
CheckCurrentScreen(UpdateView::kScreenId);
EXPECT_CALL(*mock_update_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_consolidated_consent_screen_, ShowImpl()).Times(1);
mock_update_screen_->RunExit(UpdateScreen::Result::UPDATE_NOT_REQUIRED);
CheckCurrentScreen(ConsolidatedConsentScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_consolidated_consent_screen_, HideImpl()).Times(1);
EXPECT_CALL(*mock_auto_enrollment_check_screen_, ShowImpl()).Times(1);
mock_consolidated_consent_screen_->ExitScreen(
ConsolidatedConsentScreen::Result::ACCEPTED_DEMO_ONLINE);
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_TRUE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
EXPECT_CALL(*mock_auto_enrollment_check_screen_, HideImpl()).Times(1);
mock_auto_enrollment_check_screen_->RealShow();
// Wait for auto-enrollment controller to encounter the connection error.
WaitForAutoEnrollmentState(kAutoEnrollmentConnectionError);
// The error screen shows up if device state could not be retrieved.
CheckCurrentScreen(AutoEnrollmentCheckScreenView::kScreenId);
EXPECT_EQ(AutoEnrollmentCheckScreenView::kScreenId.AsId(),
GetErrorScreen()->GetParentScreen());
base::Value::Dict device_state;
device_state.Set(policy::kDeviceStateMode,
base::Value(policy::kDeviceStateModeDisabled));
device_state.Set(policy::kDeviceStateDisabledMessage,
base::Value(kDisabledMessage));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
EXPECT_CALL(*device_disabled_screen_view_,
Show(Field(&DeviceDisabledScreenView::Params::message,
Eq(kDisabledMessage))))
.Times(1);
mock_auto_enrollment_check_screen_->ExitScreen();
base::RunLoop().RunUntilIdle();
ResetAutoEnrollmentCheckScreen();
CheckCurrentScreen(DeviceDisabledScreenView::kScreenId);
EXPECT_FALSE(StartupUtils::IsOobeCompleted());
EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress());
}
class WizardControllerOobeResumeTest : public WizardControllerTest {
public:
WizardControllerOobeResumeTest(const WizardControllerOobeResumeTest&) =
delete;
WizardControllerOobeResumeTest& operator=(
const WizardControllerOobeResumeTest&) = delete;
protected:
WizardControllerOobeResumeTest() = default;
// WizardControllerTest:
void SetUpOnMainThread() override {
WizardControllerTest::SetUpOnMainThread();
// Make sure that OOBE is run as an "official" build.
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build =
true;
WizardController* wizard_controller =
WizardController::default_controller();
wizard_controller->SetCurrentScreen(nullptr);
// Set up the mocks for all screens.
mock_welcome_view_ = std::make_unique<MockWelcomeView>();
mock_welcome_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockWelcomeScreen>(
mock_welcome_view_->AsWeakPtr(),
base::BindRepeating(&WizardController::OnWelcomeScreenExit,
base::Unretained(wizard_controller))));
mock_enrollment_screen_view_ = std::make_unique<MockEnrollmentScreenView>();
mock_enrollment_screen_ =
MockScreenExpectLifecycle(std::make_unique<MockEnrollmentScreen>(
mock_enrollment_screen_view_->AsWeakPtr(), GetErrorScreen(),
base::BindRepeating(&WizardController::OnEnrollmentScreenExit,
base::Unretained(wizard_controller))));
}
std::unique_ptr<MockWelcomeView> mock_welcome_view_;
raw_ptr<MockWelcomeScreen, DanglingUntriaged> mock_welcome_screen_;
std::unique_ptr<MockEnrollmentScreenView> mock_enrollment_screen_view_;
raw_ptr<MockEnrollmentScreen, DanglingUntriaged> mock_enrollment_screen_;
std::unique_ptr<base::AutoReset<bool>> branded_build_override_;
};
IN_PROC_BROWSER_TEST_F(WizardControllerOobeResumeTest,
PRE_ControlFlowResumeInterruptedOobe) {
// Switch to the initial screen.
EXPECT_CALL(*mock_welcome_screen_, ShowImpl()).Times(1);
WizardController::default_controller()->AdvanceToScreen(
WelcomeView::kScreenId);
CheckCurrentScreen(WelcomeView::kScreenId);
EXPECT_CALL(*mock_enrollment_screen_view_,
SetEnrollmentConfig(
EnrollmentModeMatches(policy::EnrollmentConfig::MODE_MANUAL)))
.Times(1);
EXPECT_CALL(*mock_enrollment_screen_, ShowImpl()).Times(1);
EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
WizardController::default_controller()->AdvanceToScreen(
EnrollmentScreenView::kScreenId);
CheckCurrentScreen(EnrollmentScreenView::kScreenId);
}
IN_PROC_BROWSER_TEST_F(WizardControllerOobeResumeTest,
ControlFlowResumeInterruptedOobe) {
EXPECT_EQ(EnrollmentScreenView::kScreenId.AsId(),
WizardController::default_controller()->first_screen_for_testing());
}
class WizardControllerOnboardingResumeTest : public WizardControllerTest {
protected:
void SetUpOnMainThread() override {
cryptohome_mixin_.ApplyAuthConfigIfUserExists(
user_, test::UserAuthConfig::Create(test::kDefaultAuthSetup));
WizardControllerTest::SetUpOnMainThread();
}
DeviceStateMixin device_state_{
&mixin_host_,
DeviceStateMixin::State::OOBE_COMPLETED_PERMANENTLY_UNOWNED};
FakeGaiaMixin gaia_mixin_{&mixin_host_};
CryptohomeMixin cryptohome_mixin_{&mixin_host_};
LoginManagerMixin login_mixin_{&mixin_host_, LoginManagerMixin::UserList(),
&gaia_mixin_};
AccountId user_{AccountId::FromUserEmailGaiaId(test::kTestEmail,
GaiaId(test::kTestGaiaId))};
};
IN_PROC_BROWSER_TEST_F(WizardControllerOnboardingResumeTest,
PRE_ControlFlowResumeInterruptedOnboarding) {
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
LoginManagerMixin::TestUserInfo test_user(user_);
login_mixin_.LoginWithDefaultContext(test_user);
OobeScreenExitWaiter(UserCreationView::kScreenId).Wait();
WizardController::default_controller()->AdvanceToScreen(
MarketingOptInScreenView::kScreenId);
OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
}
IN_PROC_BROWSER_TEST_F(WizardControllerOnboardingResumeTest,
ControlFlowResumeInterruptedOnboarding) {
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
login_mixin_.LoginAsNewRegularUser();
OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
}
class WizardControllerCellularFirstTest : public WizardControllerFlowTest {
public:
WizardControllerCellularFirstTest(const WizardControllerCellularFirstTest&) =
delete;
WizardControllerCellularFirstTest& operator=(
const WizardControllerCellularFirstTest&) = delete;
protected:
WizardControllerCellularFirstTest() = default;
// WizardControllerFlowTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerFlowTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kCellularFirst);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerCellularFirstTest, CellularFirstFlow) {
TestControlFlowMain();
}
class WizardControllerOobeConfigurationTest : public WizardControllerTest {
public:
WizardControllerOobeConfigurationTest(
const WizardControllerOobeConfigurationTest&) = delete;
WizardControllerOobeConfigurationTest& operator=(
const WizardControllerOobeConfigurationTest&) = delete;
protected:
WizardControllerOobeConfigurationTest() = default;
// WizardControllerTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerTest::SetUpCommandLine(command_line);
base::FilePath configuration_file;
ASSERT_TRUE(chromeos::test_utils::GetTestDataPath(
"oobe_configuration", "non_empty_configuration.json",
&configuration_file));
command_line->AppendSwitchPath(chromeos::switches::kFakeOobeConfiguration,
configuration_file);
}
};
IN_PROC_BROWSER_TEST_F(WizardControllerOobeConfigurationTest,
ConfigurationIsLoaded) {
OobeScreenWaiter(WelcomeView::kScreenId).Wait();
WelcomeScreen* screen =
WizardController::default_controller()->GetScreen<WelcomeScreen>();
const base::Value::Dict& configuration = screen->GetConfigurationForTesting();
EXPECT_FALSE(configuration.empty());
}
// Verifies that incomplete token-based enrollment flows (e.g. device is
// rebooted after enrollment fails) resume enrollment without issue. See
// b/336337134 for more details.
class WizardControllerEnrollmentTokenRebootTest
: public WizardControllerTest,
public LocalStateMixin::Delegate {
public:
WizardControllerEnrollmentTokenRebootTest(
const WizardControllerEnrollmentTokenRebootTest&) = delete;
WizardControllerEnrollmentTokenRebootTest operator=(
const WizardControllerEnrollmentTokenRebootTest&) = delete;
protected:
WizardControllerEnrollmentTokenRebootTest() = default;
// WizardControllerTest:
void SetUpCommandLine(base::CommandLine* command_line) override {
WizardControllerTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(ash::switches::kRevenBranding);
base::FilePath configuration_file;
ASSERT_TRUE(chromeos::test_utils::GetTestDataPath(
"oobe_configuration", "enrollment_token_configuration.json",
&configuration_file));
command_line->AppendSwitchPath(chromeos::switches::kFakeOobeConfiguration,
configuration_file);
}
void SetUpLocalState() override {
// Simulate device having previously gone through state determination.
base::Value::Dict device_state;
device_state.Set(
policy::kDeviceStateMode,
base::Value(policy::kDeviceStateInitialModeTokenEnrollment));
g_browser_process->local_state()->SetDict(prefs::kServerBackedDeviceState,
std::move(device_state));
}
private:
LocalStateMixin local_state_mixin_{&mixin_host_, this};
};
IN_PROC_BROWSER_TEST_F(WizardControllerEnrollmentTokenRebootTest,
ConfigurationIsLoaded) {
OobeScreenWaiter(WelcomeView::kScreenId).Wait();
WelcomeScreen* screen =
WizardController::default_controller()->GetScreen<WelcomeScreen>();
const base::Value::Dict& configuration = screen->GetConfigurationForTesting();
EXPECT_FALSE(configuration.empty());
}
class WizardControllerRemoteActivityNotificationTest
: public WizardControllerTest,
public LocalStateMixin::Delegate {
public:
WizardControllerRemoteActivityNotificationTest(
const WizardControllerRemoteActivityNotificationTest&) = delete;
WizardControllerRemoteActivityNotificationTest& operator=(
const WizardControllerRemoteActivityNotificationTest&) = delete;
protected:
WizardControllerRemoteActivityNotificationTest() = default;
~WizardControllerRemoteActivityNotificationTest() override = default;
// WizardControllerTest:
void SetUpInProcessBrowserTestFixture() override {
WizardControllerTest::SetUpInProcessBrowserTestFixture();
feature_list_.InitAndEnableFeature(
remoting::features::kEnableCrdAdminRemoteAccessV2);
login_manager_mixin_.AppendRegularUsers(1);
}
void SetUpOnMainThread() override {
WizardControllerTest::SetUpOnMainThread();
}
// LocalStateMixin::Delegate:
void SetUpLocalState() override { StartupUtils::MarkOobeCompleted(); }
void SetPref(const std::string& pref, bool value) {
local_state()->SetBoolean(pref, value);
}
bool GetPref(const std::string& pref) {
return local_state()->GetBoolean(pref);
}
PrefService* local_state() { return g_browser_process->local_state(); }
bool IsCurrentScreen(OobeScreenId screen) {
BaseScreen* current_screen =
WizardController::default_controller()->current_screen();
const std::string actual_screen =
current_screen ? current_screen->screen_id().name : "nullptr";
const std::string expected_screen = screen.name;
return actual_screen == expected_screen;
}
bool IsRemoteActivityScreenVisible() {
return LoginScreenTestApi::IsOobeDialogVisible() &&
IsCurrentScreen(RemoteActivityNotificationView::kScreenId);
}
private:
base::test::ScopedFeatureList feature_list_;
LoginManagerMixin login_manager_mixin_{&mixin_host_};
LocalStateMixin local_state_mixin_{&mixin_host_, this};
};
class RemoteActivityNotificationTestWhenPrefIsSet
: public WizardControllerRemoteActivityNotificationTest {
void SetUpLocalState() override {
SetPref(prefs::kRemoteAdminWasPresent, true);
}
};
class RemoteActivityNotificationTestWhenPrefIsNotSet
: public WizardControllerRemoteActivityNotificationTest {
void SetUpLocalState() override {
SetPref(prefs::kRemoteAdminWasPresent, false);
}
};
IN_PROC_BROWSER_TEST_F(RemoteActivityNotificationTestWhenPrefIsSet,
ShouldSetPrefOnRemoteActivityScreenExit) {
OobeScreenWaiter(RemoteActivityNotificationView::kScreenId).Wait();
CheckCurrentScreen(RemoteActivityNotificationView::kScreenId);
ASSERT_TRUE(GetPref(prefs::kRemoteAdminWasPresent));
ASSERT_TRUE(LoginScreenTestApi::IsOobeDialogVisible());
test::OobeJS().ClickOnPath({"remote-activity-notification", "cancelButton"});
test::TestPredicateWaiter(base::BindRepeating([]() {
return !LoginScreenTestApi::IsOobeDialogVisible();
})).Wait();
EXPECT_FALSE(IsRemoteActivityScreenVisible());
EXPECT_FALSE(GetPref(prefs::kRemoteAdminWasPresent));
}
IN_PROC_BROWSER_TEST_F(RemoteActivityNotificationTestWhenPrefIsNotSet,
NotificationShouldNotBeVisible) {
ASSERT_FALSE(GetPref(prefs::kRemoteAdminWasPresent));
EXPECT_FALSE(IsRemoteActivityScreenVisible());
}
class RemoteActivityNotificationTestWhenNoLoginAccountPresentTest
: public WizardControllerTest {
public:
// WizardControllerTest:
void SetUpInProcessBrowserTestFixture() override {
WizardControllerTest::SetUpInProcessBrowserTestFixture();
feature_list_.InitAndEnableFeature(
remoting::features::kEnableCrdAdminRemoteAccessV2);
}
void SetUpOnMainThread() override {
WizardControllerTest::SetUpOnMainThread();
}
PrefService* local_state() { return g_browser_process->local_state(); }
protected:
base::test::ScopedFeatureList feature_list_;
DeviceStateMixin device_state_{&mixin_host_,
DeviceStateMixin::State::BEFORE_OOBE};
FakeGaiaMixin gaia_mixin_{&mixin_host_};
LoginManagerMixin login_mixin_{&mixin_host_, LoginManagerMixin::UserList(),
&gaia_mixin_};
};
IN_PROC_BROWSER_TEST_F(
RemoteActivityNotificationTestWhenNoLoginAccountPresentTest,
PRE_ShouldGoToPreviousScreenWhenNotificationIsDismissed) {
CheckCurrentScreen(UserCreationView::kScreenId);
local_state()->SetBoolean(prefs::kRemoteAdminWasPresent, true);
}
IN_PROC_BROWSER_TEST_F(
RemoteActivityNotificationTestWhenNoLoginAccountPresentTest,
ShouldGoToPreviousScreenWhenNotificationIsDismissed) {
OobeScreenWaiter(RemoteActivityNotificationView::kScreenId).Wait();
CheckCurrentScreen(RemoteActivityNotificationView::kScreenId);
test::OobeJS().ClickOnPath({"remote-activity-notification", "cancelButton"});
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
CheckCurrentScreen(UserCreationView::kScreenId);
}
class WizardControllerThemeSelectionTest : public WizardControllerTest {
protected:
FakeGaiaMixin gaia_mixin_{&mixin_host_};
LoginManagerMixin login_mixin_{&mixin_host_, LoginManagerMixin::UserList(),
&gaia_mixin_};
};
IN_PROC_BROWSER_TEST_F(WizardControllerThemeSelectionTest,
TransitionToMarketingOptIn) {
LoginDisplayHost::default_host()
->GetWizardContextForTesting()
->skip_choobe_for_tests = true;
LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true;
login_mixin_.LoginAsNewRegularUser();
WizardController::default_controller()->AdvanceToScreen(
ThemeSelectionScreenView::kScreenId);
test::OobeJS().ClickOnPath({"theme-selection", "nextButton"});
OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
}
IN_PROC_BROWSER_TEST_F(WizardControllerThemeSelectionTest,
TransitionToThemeSelection) {
LoginDisplayHost::default_host()
->GetWizardContextForTesting()
->skip_choobe_for_tests = true;
login_mixin_.LoginAsNewRegularUser();
if (features::IsOobeDisplaySizeEnabled()) {
WizardController::default_controller()->AdvanceToScreen(
DisplaySizeScreenView::kScreenId);
test::OobeJS().ClickOnPath({"display-size", "nextButton"});
} else if (features::IsOobeTouchpadScrollEnabled()) {
WizardController::default_controller()->AdvanceToScreen(
TouchpadScrollScreenView::kScreenId);
test::OobeJS().ClickOnPath({"touchpad-scroll", "nextButton"});
} else {
WizardController::default_controller()->AdvanceToScreen(
GestureNavigationScreenView::kScreenId);
}
OobeScreenWaiter(ThemeSelectionScreenView::kScreenId).Wait();
}
class GaiaInfoTest : public WizardControllerTest {
public:
GaiaInfoTest() {
feature_list_.InitAndEnableFeature(features::kOobeGaiaInfoScreen);
}
protected:
base::test::ScopedFeatureList feature_list_;
};
class GaiaInfoScreenForEnterpriseEnrollmentTest : public GaiaInfoTest {
private:
DeviceStateMixin device_state_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
};
IN_PROC_BROWSER_TEST_F(GaiaInfoScreenForEnterpriseEnrollmentTest,
SkippingGaiaInfo) {
WizardController::default_controller()->AdvanceToScreen(
GaiaInfoScreenView::kScreenId);
OobeScreenWaiter(GaiaView::kScreenId).Wait();
}
IN_PROC_BROWSER_TEST_F(GaiaInfoTest, TransitionToGaiaInfo) {
WaitForOobeUI();
WizardController::default_controller()->AdvanceToScreen(
UserCreationView::kScreenId);
test::OobeJS().ClickOnPath({"user-creation", "selfButton"});
test::OobeJS().ClickOnPath({"user-creation", "nextButton"});
test::WaitForConsumerUpdateScreen();
test::ExitConsumerUpdateScreenNoUpdate();
OobeScreenWaiter(GaiaInfoScreenView::kScreenId).Wait();
}
IN_PROC_BROWSER_TEST_F(GaiaInfoTest, TransitionFromGaiaInfo) {
WaitForOobeUI();
WizardController::default_controller()->AdvanceToScreen(
GaiaInfoScreenView::kScreenId);
test::OobeJS().ClickOnPath({"gaia-info", "nextButton"});
OobeScreenWaiter(GaiaView::kScreenId).Wait();
}
IN_PROC_BROWSER_TEST_F(GaiaInfoTest, SkipGaiaInfoForChildAccount) {
WaitForOobeUI();
WizardController::default_controller()->AdvanceToScreen(
UserCreationView::kScreenId);
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
test::OobeJS().ClickOnPath({"user-creation", "childButton"});
test::OobeJS().ClickOnPath({"user-creation", "nextButton"});
test::OobeJS().ClickOnPath({"user-creation", "childAccountButton"});
test::OobeJS().ClickOnPath({"user-creation", "childSetupNextButton"});
test::WaitForConsumerUpdateScreen();
test::ExitConsumerUpdateScreenNoUpdate();
OobeScreenWaiter(AddChildScreenView::kScreenId).Wait();
}
class WizardControllerGaiaTest : public GaiaInfoTest {
protected:
FakeGaiaMixin fake_gaia_{&mixin_host_};
};
IN_PROC_BROWSER_TEST_F(WizardControllerGaiaTest, GoBackToGaiaInfo) {
LoginDisplayHost::default_host()
->GetWizardContext()
->is_user_creation_enabled = true;
WaitForOobeUI();
WizardController::default_controller()->AdvanceToScreen(
GaiaInfoScreenView::kScreenId);
test::OobeJS().ClickOnPath({"gaia-info", "nextButton"});
OobeScreenWaiter(GaiaView::kScreenId).Wait();
test::OobeJS().ClickOnPath(
{"gaia-signin", "signin-frame-dialog", "signin-back-button"});
if (features::IsOobeSoftwareUpdateEnabled()) {
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
} else {
OobeScreenWaiter(GaiaInfoScreenView::kScreenId).Wait();
}
}
IN_PROC_BROWSER_TEST_F(WizardControllerGaiaTest,
GoBackSkippingGaiaInfoInAddPersonFlow) {
LoginDisplayHost::default_host()
->GetWizardContext()
->is_user_creation_enabled = true;
LoginDisplayHost::default_host()->GetWizardContext()->is_add_person_flow =
true;
WaitForOobeUI();
WizardController::default_controller()->AdvanceToScreen(
GaiaInfoScreenView::kScreenId);
OobeScreenWaiter(GaiaView::kScreenId).Wait();
test::OobeJS().ClickOnPath(
{"gaia-signin", "signin-frame-dialog", "signin-back-button"});
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
}
class GoingBackFromGaiaScreenInChildFlowTest
: public GaiaInfoTest,
public testing::WithParamInterface<std::tuple<bool, std::string>> {
FakeGaiaMixin fake_gaia_{&mixin_host_};
};
IN_PROC_BROWSER_TEST_P(GoingBackFromGaiaScreenInChildFlowTest,
SkippingGaiaInfoScreen) {
LoginDisplayHost::default_host()->GetWizardContext()->is_add_person_flow =
std::get<0>(GetParam());
WizardController::default_controller()->AdvanceToScreen(
UserCreationView::kScreenId);
OobeScreenWaiter(UserCreationView::kScreenId).Wait();
test::OobeJS().ClickOnPath({"user-creation", "childButton"});
test::OobeJS().ClickOnPath({"user-creation", "nextButton"});
test::OobeJS().ClickOnPath({"user-creation", "childAccountButton"});
test::OobeJS().ClickOnPath({"user-creation", "childSetupNextButton"});
if (!LoginDisplayHost::default_host()
->GetWizardContext()
->is_add_person_flow) {
test::WaitForConsumerUpdateScreen();
test::ExitConsumerUpdateScreenNoUpdate();
}
OobeScreenWaiter(AddChildScreenView::kScreenId).Wait();
test::OobeJS().ClickOnPath({"add-child", std::get<1>(GetParam())});
test::OobeJS().ClickOnPath({"add-child", "childNextButton"});
OobeScreenWaiter(GaiaView::kScreenId).Wait();
test::OobeJS().ClickOnPath(
{"gaia-signin", "signin-frame-dialog", "signin-back-button"});
OobeScreenWaiter(AddChildScreenView::kScreenId).Wait();
}
INSTANTIATE_TEST_SUITE_P(
All,
GoingBackFromGaiaScreenInChildFlowTest,
testing::Values(std::make_tuple(true, "childCreateButton"),
std::make_tuple(true, "childSignInButton"),
std::make_tuple(false, "childCreateButton"),
std::make_tuple(false, "childSignInButton")));
// TODO(nkostylev): Add test for WebUI accelerators http://crosbug.com/22571
// TODO(merkulova): Add tests for bluetooth HID detection screen variations when
// UI and logic is ready. http://crbug.com/127016
// TODO(khmel): Add tests for ARC OptIn flow.
// http://crbug.com/651144
// TODO(fukino): Add tests for encryption migration UI.
// http://crbug.com/706017
// TODO(alemate): Add tests for Sync Consent UI.
// TODO(rsgingerrs): Add tests for Recommend Apps UI.
// TODO(alemate): Add tests for Marketing Opt-In.
// TODO(khorimoto): Add tests for MultiDevice Setup UI.
} // namespace ash