Commit d0dd47ab authored by Lucas Tenório's avatar Lucas Tenório Committed by Commit Bot

Add tests for authenticated Supervision Onboarding pages.

To power the tests we need to setup an HTTP server to handle access
token requests and supervision pages.
It's expected that the Supervision server will return a custom HTTP
header with an specific value when the user is eligible to see the
flow.
We test cases where the server doesn't send the header as well as
when the header doesn't contain the values that we want.

Bug: 958995
Change-Id: Ib8017678951ba9da1ae9b7b5b801c755ee2f7533
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1611038Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Reviewed-by: default avatarToni Baržić <tbarzic@chromium.org>
Commit-Queue: Lucas Tenório <ltenorio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661083}
parent ec6e7f1c
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "chrome/browser/chromeos/login/login_wizard.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/mixin_based_in_process_browser_test.h"
#include "chrome/browser/chromeos/login/oobe_screen.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/js_checker.h"
#include "chrome/browser/chromeos/login/test/login_manager_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/oobe_screen_waiter.h"
...@@ -25,14 +27,26 @@ ...@@ -25,14 +27,26 @@
#include "chrome/browser/ui/webui/chromeos/login/supervision_onboarding_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/supervision_onboarding_screen_handler.h"
#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_switches.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 {
namespace { namespace {
constexpr char kTestUser[] = "test-user1@gmail.com"; constexpr char kTestUser[] = "test-user1@gmail.com";
constexpr char kTestOnboardingPageUrl[] = constexpr char kTestUserGaiaId[] = "test-user1-gaia";
"https://families.google.com/families";
constexpr char kTestStartPageRelativeUrl[] = "/families/onboarding/start";
constexpr char kTestCustomHttpHeaderKey[] =
"test-supervision-onboarding-header";
chromeos::OobeUI* GetOobeUI() { chromeos::OobeUI* GetOobeUI() {
auto* host = chromeos::LoginDisplayHost::default_host(); auto* host = chromeos::LoginDisplayHost::default_host();
...@@ -41,18 +55,104 @@ chromeos::OobeUI* GetOobeUI() { ...@@ -41,18 +55,104 @@ chromeos::OobeUI* GetOobeUI() {
} // namespace } // namespace
class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest { // 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: public:
SupervisionOnboardingTest() = default; explicit FakeSupervisionServer(net::EmbeddedTestServer* test_server) {
~SupervisionOnboardingTest() override = default; 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();
}
GURL url_filter_pattern() const { return test_server_->GetURL("/*"); }
GURL start_page_url() {
return test_server_->GetURL(kTestStartPageRelativeUrl);
}
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 != kTestStartPageRelativeUrl)
return nullptr;
UpdateVerificationData(request);
auto response = std::make_unique<BasicHttpResponse>();
if (custom_http_header_value_.has_value()) {
response->AddCustomHeader(kTestCustomHttpHeaderKey,
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;
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( host_resolver()->AddRule("*", "127.0.0.1");
chromeos::switches::kSupervisionOnboardingStartPageUrl,
kTestOnboardingPageUrl);
login_manager_.LoginAndWaitForActiveSession( fake_gaia_.SetupFakeGaiaForLogin(kTestUser, kTestUserGaiaId,
LoginManagerMixin::CreateDefaultUserContext(test_user_)); FakeGaiaMixin::kFakeRefreshToken);
// Since we will login after this method returns, we need to set this
// to prevent Chrome from trying to quit after login.
login_manager_.set_should_launch_browser(true);
MixinBasedInProcessBrowserTest::SetUpOnMainThread();
}
void LoginAndShowScreen() {
UserContext user_context =
LoginManagerMixin::CreateDefaultUserContext(test_user_);
user_context.SetRefreshToken(FakeGaiaMixin::kFakeRefreshToken);
login_manager_.LoginAndWaitForActiveSession(user_context);
ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW); ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW);
WizardController::default_controller() WizardController::default_controller()
...@@ -61,34 +161,15 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest { ...@@ -61,34 +161,15 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest {
auto supervision_onboarding_screen = auto supervision_onboarding_screen =
std::make_unique<SupervisionOnboardingScreen>( std::make_unique<SupervisionOnboardingScreen>(
GetOobeUI()->GetView<SupervisionOnboardingScreenHandler>(), GetOobeUI()->GetView<SupervisionOnboardingScreenHandler>(),
base::BindRepeating(&SupervisionOnboardingTest::HandleScreenExit, base::BindRepeating(
base::Unretained(this))); &SupervisionOnboardingBaseTest::HandleScreenExit,
base::Unretained(this)));
supervision_onboarding_screen_ = supervision_onboarding_screen.get(); supervision_onboarding_screen_ = supervision_onboarding_screen.get();
WizardController::default_controller() WizardController::default_controller()
->screen_manager() ->screen_manager()
->SetScreenForTesting(std::move(supervision_onboarding_screen)); ->SetScreenForTesting(std::move(supervision_onboarding_screen));
MixinBasedInProcessBrowserTest::SetUpOnMainThread();
}
void TurnOnFeature() {
feature_list_.InitAndEnableFeature(
features::kEnableSupervisionOnboardingScreens);
}
void ShowAndWaitForScreen() {
supervision_onboarding_screen_->Show(); supervision_onboarding_screen_->Show();
OobeScreenWaiter screen_waiter(SupervisionOnboardingScreenView::kScreenId);
screen_waiter.set_assert_next_screen();
screen_waiter.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() { void WaitForScreenExit() {
...@@ -100,8 +181,9 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest { ...@@ -100,8 +181,9 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest {
run_loop.Run(); run_loop.Run();
} }
FakeSupervisionServer* supervision_server() { return &supervision_server_; }
SupervisionOnboardingScreen* supervision_onboarding_screen_; SupervisionOnboardingScreen* supervision_onboarding_screen_;
base::test::ScopedFeatureList feature_list_;
private: private:
void HandleScreenExit() { void HandleScreenExit() {
...@@ -114,36 +196,132 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest { ...@@ -114,36 +196,132 @@ class SupervisionOnboardingTest : public MixinBasedInProcessBrowserTest {
bool screen_exited_ = false; bool screen_exited_ = false;
base::OnceClosure screen_exit_callback_; base::OnceClosure screen_exit_callback_;
const LoginManagerMixin::TestUserInfo test_user_{ const AccountId test_account_id_ =
AccountId::FromUserEmailGaiaId(kTestUser, kTestUser)}; AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId);
const LoginManagerMixin::TestUserInfo test_user_{test_account_id_};
EmbeddedTestServerSetupMixin embedded_test_server_{&mixin_host_,
embedded_test_server()};
FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
LoginManagerMixin login_manager_{&mixin_host_, {test_user_}}; LoginManagerMixin login_manager_{&mixin_host_, {test_user_}};
FakeSupervisionServer supervision_server_{embedded_test_server()};
}; };
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, class SupervisionOnboardingTest : public SupervisionOnboardingBaseTest {
public:
SupervisionOnboardingTest() = default;
~SupervisionOnboardingTest() override = default;
void SetUp() override {
feature_list_.InitAndEnableFeature(
features::kEnableSupervisionOnboardingScreens);
SupervisionOnboardingBaseTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(
chromeos::switches::kSupervisionOnboardingPageUrlPattern,
supervision_server()->url_filter_pattern().spec());
command_line->AppendSwitchASCII(
chromeos::switches::kSupervisionOnboardingStartPageUrl,
supervision_server()->start_page_url().spec());
command_line->AppendSwitchASCII(
chromeos::switches::kSupervisionOnboardingHttpResponseHeader,
kTestCustomHttpHeaderKey);
// 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.
ExpectCustomHttpHeaderValue("user-eligible");
supervision_server()->set_custom_http_header_value("user-eligible");
SupervisionOnboardingBaseTest::SetUpCommandLine(command_line);
}
// Sets the flow to expect the given header value in server responses. If
// the value is not present, we should exit the flow.
void ExpectCustomHttpHeaderValue(
const std::string& custom_http_header_value) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
chromeos::switches::kSupervisionOnboardingHttpResponseHeaderValue,
custom_http_header_value);
}
void WaitForScreen() {
OobeScreenWaiter screen_waiter(SupervisionOnboardingScreenView::kScreenId);
screen_waiter.set_assert_next_screen();
screen_waiter.Wait();
test::OobeJS()
.CreateVisibilityWaiter(true,
{"supervision-onboarding", "contentWebview"})
->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);
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingBaseTest,
ExitImmediatelyWhenFeatureIsOff) { ExitImmediatelyWhenFeatureIsOff) {
supervision_onboarding_screen_->Show(); LoginAndShowScreen();
WaitForScreenExit(); WaitForScreenExit();
EXPECT_EQ(0u, supervision_server()->GetReceivedRequestsCount());
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest,
ExitWhenServerDoesNotReturnHeader) {
supervision_server()->clear_custom_http_header_value();
LoginAndShowScreen();
WaitForScreenExit();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
}
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest,
ExitWhenServerSendsWrongHeader) {
ExpectCustomHttpHeaderValue("user-eligible-for-supervision");
supervision_server()->set_custom_http_header_value("user-not-eligible");
LoginAndShowScreen();
WaitForScreenExit();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
} }
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, NextButtonExitsScreen) { IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, NextButtonExitsScreen) {
TurnOnFeature(); LoginAndShowScreen();
ShowAndWaitForScreen(); WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("next-button"); ClickButton("next-button");
WaitForScreenExit(); WaitForScreenExit();
} }
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, BackButtonExitsScreen) { IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, BackButtonExitsScreen) {
TurnOnFeature(); LoginAndShowScreen();
ShowAndWaitForScreen(); WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("back-button"); ClickButton("back-button");
WaitForScreenExit(); WaitForScreenExit();
} }
IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, SkipButtonExitsScreen) { IN_PROC_BROWSER_TEST_F(SupervisionOnboardingTest, SkipButtonExitsScreen) {
TurnOnFeature(); LoginAndShowScreen();
ShowAndWaitForScreen(); WaitForScreen();
EXPECT_EQ(1u, supervision_server()->GetReceivedRequestsCount());
ClickButton("skip-button"); ClickButton("skip-button");
WaitForScreenExit(); WaitForScreenExit();
......
...@@ -16,7 +16,6 @@ namespace chromeos { ...@@ -16,7 +16,6 @@ namespace chromeos {
namespace { namespace {
constexpr char kGAIAHost[] = "accounts.google.com"; constexpr char kGAIAHost[] = "accounts.google.com";
constexpr char kTestAllScopeAccessToken[] = "fake-all-scope-token";
} // namespace } // namespace
// static // static
...@@ -26,6 +25,7 @@ const char FakeGaiaMixin::kFakeUserGaiaId[] = "fake-gaiaId"; ...@@ -26,6 +25,7 @@ const char FakeGaiaMixin::kFakeUserGaiaId[] = "fake-gaiaId";
const char FakeGaiaMixin::kFakeAuthCode[] = "fake-auth-code"; const char FakeGaiaMixin::kFakeAuthCode[] = "fake-auth-code";
const char FakeGaiaMixin::kFakeRefreshToken[] = "fake-refresh-token"; const char FakeGaiaMixin::kFakeRefreshToken[] = "fake-refresh-token";
const char FakeGaiaMixin::kEmptyUserServices[] = "[]"; const char FakeGaiaMixin::kEmptyUserServices[] = "[]";
const char FakeGaiaMixin::kFakeAllScopeAccessToken[] = "fake-all-scope-token";
const char FakeGaiaMixin::kFakeSIDCookie[] = "fake-SID-cookie"; const char FakeGaiaMixin::kFakeSIDCookie[] = "fake-SID-cookie";
const char FakeGaiaMixin::kFakeLSIDCookie[] = "fake-LSID-cookie"; const char FakeGaiaMixin::kFakeLSIDCookie[] = "fake-LSID-cookie";
...@@ -55,7 +55,7 @@ void FakeGaiaMixin::SetupFakeGaiaForLogin(const std::string& user_email, ...@@ -55,7 +55,7 @@ void FakeGaiaMixin::SetupFakeGaiaForLogin(const std::string& user_email,
fake_gaia_->MapEmailToGaiaId(user_email, gaia_id); fake_gaia_->MapEmailToGaiaId(user_email, gaia_id);
FakeGaia::AccessTokenInfo token_info; FakeGaia::AccessTokenInfo token_info;
token_info.token = kTestAllScopeAccessToken; token_info.token = kFakeAllScopeAccessToken;
token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
token_info.email = user_email; token_info.email = user_email;
token_info.any_scope = true; token_info.any_scope = true;
...@@ -80,7 +80,7 @@ void FakeGaiaMixin::SetupFakeGaiaForChildUser(const std::string& user_email, ...@@ -80,7 +80,7 @@ void FakeGaiaMixin::SetupFakeGaiaForChildUser(const std::string& user_email,
if (issue_any_scope_token) { if (issue_any_scope_token) {
FakeGaia::AccessTokenInfo all_scopes_token; FakeGaia::AccessTokenInfo all_scopes_token;
all_scopes_token.token = kTestAllScopeAccessToken; all_scopes_token.token = kFakeAllScopeAccessToken;
all_scopes_token.audience = all_scopes_token.audience =
GaiaUrls::GetInstance()->oauth2_chrome_client_id(); GaiaUrls::GetInstance()->oauth2_chrome_client_id();
all_scopes_token.email = user_email; all_scopes_token.email = user_email;
......
...@@ -28,6 +28,7 @@ class FakeGaiaMixin : public InProcessBrowserTestMixin { ...@@ -28,6 +28,7 @@ class FakeGaiaMixin : public InProcessBrowserTestMixin {
static const char kFakeAuthCode[]; static const char kFakeAuthCode[];
static const char kFakeRefreshToken[]; static const char kFakeRefreshToken[];
static const char kEmptyUserServices[]; static const char kEmptyUserServices[];
static const char kFakeAllScopeAccessToken[];
// FakeGaia is configured to return these cookies for kFakeUserEmail. // FakeGaia is configured to return these cookies for kFakeUserEmail.
static const char kFakeSIDCookie[]; static const char kFakeSIDCookie[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment