blob: 41c2ae2aadc3337b89f0c8faff14f8b4a31d4c07 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/login/screens/supervision_onboarding_screen.h"
#include <initializer_list>
#include <memory>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/chromeos/login/login_wizard.h"
#include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h"
#include "chrome/browser/chromeos/login/oobe_screen.h"
#include "chrome/browser/chromeos/login/test/embedded_test_server_mixin.h"
#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
#include "chrome/browser/chromeos/login/test/js_checker.h"
#include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
#include "chrome/browser/chromeos/login/test/user_policy_mixin.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/supervision/onboarding_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/chromeos/login/supervision_onboarding_screen_handler.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_switches.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
using net::test_server::BasicHttpResponse;
using net::test_server::HttpRequest;
using net::test_server::HttpResponse;
namespace chromeos {
namespace {
chromeos::OobeUI* GetOobeUI() {
auto* host = chromeos::LoginDisplayHost::default_host();
return host ? host->GetOobeUI() : nullptr;
}
} // namespace
// Fake HTTP server that returns the data necessary to render the Supervision
// Onboarding pages. It provides methods to customize the HTTP responses to
// include/omit custom HTTP headers that are expected by the flow.
class FakeSupervisionServer {
public:
explicit FakeSupervisionServer(net::EmbeddedTestServer* test_server) {
test_server_ = test_server;
test_server_->RegisterRequestHandler(base::BindRepeating(
&FakeSupervisionServer::HandleRequest, base::Unretained(this)));
}
~FakeSupervisionServer() = default;
// Sets the custom HTTP header that will be sent back in responses.
void set_custom_http_header_value(
const std::string& custom_http_header_value) {
custom_http_header_value_ = custom_http_header_value;
}
// Stops sending the custom header in responses.
void clear_custom_http_header_value() {
custom_http_header_value_ = base::nullopt;
}
size_t GetReceivedRequestsCount() const {
// It's safe to use the size of the access token list as a proxy to the
// number of requests. This server asserts that all requests contain an
// authentication header.
return received_auth_header_values_.size();
}
private:
std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
// We are not interested in other URLs hitting the server at this point.
// This will filter bogus requests like favicon fetches and stop us from
// handling requests that are targeting gaia.
if (request.relative_url != supervision::kOnboardingStartPageRelativeUrl)
return nullptr;
UpdateVerificationData(request);
auto response = std::make_unique<BasicHttpResponse>();
if (custom_http_header_value_.has_value()) {
response->AddCustomHeader(supervision::kExperimentHeaderName,
custom_http_header_value_.value());
}
response->set_code(net::HTTP_OK);
response->set_content("Test Supervision Onboarding content");
response->set_content_type("text/plain");
return std::move(response);
}
void UpdateVerificationData(const HttpRequest& request) {
auto auth_header =
request.headers.find(net::HttpRequestHeaders::kAuthorization);
ASSERT_NE(auth_header, request.headers.end());
ASSERT_EQ(auth_header->second,
base::StringPrintf("Bearer %s",
FakeGaiaMixin::kFakeAllScopeAccessToken));
received_auth_header_values_.push_back(auth_header->second);
}
net::EmbeddedTestServer* test_server_;
std::vector<std::string> received_auth_header_values_;
base::Optional<std::string> custom_http_header_value_ = base::nullopt;
};
class SupervisionOnboardingBaseTest : public MixinBasedInProcessBrowserTest {
public:
SupervisionOnboardingBaseTest() = default;
~SupervisionOnboardingBaseTest() override = default;
virtual bool IsFeatureOn() const = 0;
virtual bool IsChild() const = 0;
void SetUp() override {
if (IsFeatureOn()) {
feature_list_.InitAndEnableFeature(
features::kEnableSupervisionOnboardingScreens);
}
MixinBasedInProcessBrowserTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
if (IsFeatureOn()) {
command_line->AppendSwitchASCII(
switches::kSupervisionOnboardingUrlPrefix,
embedded_test_server()->base_url().spec());
// To turn on the feature properly we also ask the server to return the
// expected custom http header value. Tests that want to simulate other
// server responses can call these methods again to override this
// behavior.
supervision_server()->set_custom_http_header_value(
supervision::kDeviceOnboardingExperimentName);
}
MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
AccountId id =
IsChild() ? child_user_.account_id : regular_user_.account_id;
fake_gaia_.SetupFakeGaiaForLogin(id.GetUserEmail(), id.GetGaiaId(),
FakeGaiaMixin::kFakeRefreshToken);
LoginManagerMixin::TestUserInfo user_info =
IsChild() ? child_user_ : regular_user_;
UserContext user_context =
LoginManagerMixin::CreateDefaultUserContext(user_info);
user_context.SetRefreshToken(FakeGaiaMixin::kFakeRefreshToken);
login_manager_.LoginAndWaitForActiveSession(user_context);
ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW);
WizardController::default_controller()
->screen_manager()
->DeleteScreenForTesting(SupervisionOnboardingScreenView::kScreenId);
auto supervision_onboarding_screen =
std::make_unique<SupervisionOnboardingScreen>(
GetOobeUI()->GetView<SupervisionOnboardingScreenHandler>(),
base::BindRepeating(
&SupervisionOnboardingBaseTest::HandleScreenExit,
base::Unretained(this)));
supervision_onboarding_screen_ = supervision_onboarding_screen.get();
WizardController::default_controller()
->screen_manager()
->SetScreenForTesting(std::move(supervision_onboarding_screen));
MixinBasedInProcessBrowserTest::SetUpOnMainThread();
}
void ShowScreen() { supervision_onboarding_screen_->Show(); }
void WaitForScreen() {
OobeScreenWaiter screen_waiter(SupervisionOnboardingScreenView::kScreenId);
screen_waiter.set_assert_next_screen();
screen_waiter.Wait();
test::OobeJS()
.CreateVisibilityWaiter(
true, {"supervision-onboarding", "supervision-onboarding-content"})
->Wait();
}
void ClickButton(const std::string& button_id) {
std::initializer_list<base::StringPiece> button_path = {
"supervision-onboarding", button_id};
test::OobeJS().CreateEnabledWaiter(true, button_path)->Wait();
test::OobeJS().TapOnPath(button_path);
}
void WaitForScreenExit() {
if (screen_exited_)
return;
base::RunLoop run_loop;
screen_exit_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
FakeSupervisionServer* supervision_server() { return &supervision_server_; }
SupervisionOnboardingScreen* supervision_onboarding_screen_;
private:
void HandleScreenExit() {
ASSERT_FALSE(screen_exited_);
screen_exited_ = true;
if (screen_exit_callback_)
std::move(screen_exit_callback_).Run();
}
base::test::ScopedFeatureList feature_list_;
bool screen_exited_ = false;
base::OnceClosure screen_exit_callback_;
const LoginManagerMixin::TestUserInfo regular_user_{
AccountId::FromUserEmailGaiaId("test-regular-user@gmail.com",
"test-regular-user-gaia-id")};
const LoginManagerMixin::TestUserInfo child_user_{
AccountId::FromUserEmailGaiaId("test-child-user@gmail.com",
"test-child-user-gaia-id"),
user_manager::USER_TYPE_CHILD};
EmbeddedTestServerSetupMixin embedded_test_server_{&mixin_host_,
embedded_test_server()};
FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
LoginManagerMixin login_manager_{&mixin_host_, {regular_user_, child_user_}};
LocalPolicyTestServerMixin local_policy_mixin_{&mixin_host_};
UserPolicyMixin user_policy_{&mixin_host_, child_user_.account_id,
&local_policy_mixin_};
FakeSupervisionServer supervision_server_{embedded_test_server()};
};
class SupervisionOnboardingRegularUserTest
: public SupervisionOnboardingBaseTest {
public:
SupervisionOnboardingRegularUserTest() = default;
~SupervisionOnboardingRegularUserTest() override = default;
bool IsFeatureOn() const override { return true; }
bool IsChild() const override { return false; }
};
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingRegularUserTest,
FlowExitsImmediately) {
ShowScreen();
WaitForScreenExit();
EXPECT_EQ(0u, supervision_server()->GetReceivedRequestsCount());
}
class SupervisionOnboardingFeatureTurnedOffTest
: public SupervisionOnboardingBaseTest {
public:
SupervisionOnboardingFeatureTurnedOffTest() = default;
~SupervisionOnboardingFeatureTurnedOffTest() override = default;
bool IsFeatureOn() const override { return false; }
bool IsChild() const override { return true; }
};
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingFeatureTurnedOffTest,
FlowExitsImmediately) {
ShowScreen();
WaitForScreenExit();
EXPECT_EQ(0u, supervision_server()->GetReceivedRequestsCount());
}
class SupervisionOnboardingTest : public SupervisionOnboardingBaseTest {
public:
SupervisionOnboardingTest() = default;
~SupervisionOnboardingTest() override = default;
bool IsFeatureOn() const override { return true; }
bool IsChild() const override { return true; }
};
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest,
ExitWhenServerDoesNotReturnHeader) {
supervision_server()->clear_custom_http_header_value();
ShowScreen();
WaitForScreenExit();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest,
ExitWhenServerSendsWrongHeader) {
supervision_server()->set_custom_http_header_value("wrong_header_value");
ShowScreen();
WaitForScreenExit();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, NextButtonExitsScreen) {
ShowScreen();
WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("supervision-onboarding-next-button");
WaitForScreenExit();
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, BackButtonExitsScreen) {
ShowScreen();
WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("supervision-onboarding-back-button");
WaitForScreenExit();
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, SkipButtonExitsScreen) {
ShowScreen();
WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("supervision-onboarding-skip-button");
WaitForScreenExit();
}
} // namespace chromeos