blob: 50e3954c706a2a5edce036a2b3958ede50eb2da0 [file] [log] [blame]
// Copyright 2016 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 <memory>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/policy/core/browser/browser_policy_connector_base.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/permission_controller_delegate.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/no_renderer_crashes_assertion.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/lib/browser/policy/headless_mode_policy.h"
#include "headless/lib/headless_macros.h"
#include "headless/public/devtools/domains/inspector.h"
#include "headless/public/devtools/domains/network.h"
#include "headless/public/devtools/domains/page.h"
#include "headless/public/devtools/domains/tracing.h"
#include "headless/public/headless_browser.h"
#include "headless/public/headless_devtools_client.h"
#include "headless/public/headless_devtools_target.h"
#include "headless/public/headless_web_contents.h"
#include "headless/test/headless_browser_test.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_status_flags.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/chrome_debug_urls.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/geometry/size.h"
#if defined(OS_MAC)
#include "third_party/crashpad/crashpad/client/crash_report_database.h" // nogncheck
#endif
using testing::UnorderedElementsAre;
namespace headless {
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyBrowserContext) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
browser_context->Close();
EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
CreateAndDoNotDestroyBrowserContext) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
// We check that HeadlessBrowser correctly handles non-closed BrowserContexts.
// We can rely on Chromium DCHECKs to capture this.
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().Build();
EXPECT_TRUE(web_contents);
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
EXPECT_THAT(browser_context->GetAllWebContents(),
UnorderedElementsAre(web_contents));
// TODO(skyostil): Verify viewport dimensions once we can.
web_contents->Close();
EXPECT_TRUE(browser_context->GetAllWebContents().empty());
browser_context->Close();
EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
WebContentsAreDestroyedWithContext) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().Build();
EXPECT_TRUE(web_contents);
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
EXPECT_THAT(browser_context->GetAllWebContents(),
UnorderedElementsAre(web_contents));
browser_context->Close();
EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
// If WebContents are not destroyed, Chromium DCHECKs will capture this.
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDoNotDestroyWebContents) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().Build();
EXPECT_TRUE(web_contents);
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
EXPECT_THAT(browser_context->GetAllWebContents(),
UnorderedElementsAre(web_contents));
// If WebContents are not destroyed, Chromium DCHECKs will capture this.
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DestroyAndCreateTwoWebContents) {
HeadlessBrowserContext* browser_context1 =
browser()->CreateBrowserContextBuilder().Build();
EXPECT_TRUE(browser_context1);
HeadlessWebContents* web_contents1 =
browser_context1->CreateWebContentsBuilder().Build();
EXPECT_TRUE(web_contents1);
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context1));
EXPECT_THAT(browser_context1->GetAllWebContents(),
UnorderedElementsAre(web_contents1));
HeadlessBrowserContext* browser_context2 =
browser()->CreateBrowserContextBuilder().Build();
EXPECT_TRUE(browser_context2);
HeadlessWebContents* web_contents2 =
browser_context2->CreateWebContentsBuilder().Build();
EXPECT_TRUE(web_contents2);
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context1, browser_context2));
EXPECT_THAT(browser_context1->GetAllWebContents(),
UnorderedElementsAre(web_contents1));
EXPECT_THAT(browser_context2->GetAllWebContents(),
UnorderedElementsAre(web_contents2));
browser_context1->Close();
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context2));
EXPECT_THAT(browser_context2->GetAllWebContents(),
UnorderedElementsAre(web_contents2));
browser_context2->Close();
EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateWithBadURL) {
GURL bad_url("not_valid");
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(bad_url)
.Build();
EXPECT_FALSE(web_contents);
EXPECT_TRUE(browser_context->GetAllWebContents().empty());
}
class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest {
public:
HeadlessBrowserTestWithProxy()
: proxy_server_(net::EmbeddedTestServer::TYPE_HTTP) {
proxy_server_.AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("headless/test/data")));
}
void SetUp() override {
ASSERT_TRUE(proxy_server_.Start());
HeadlessBrowserTest::SetUp();
}
void TearDown() override {
EXPECT_TRUE(proxy_server_.ShutdownAndWaitUntilComplete());
HeadlessBrowserTest::TearDown();
}
net::EmbeddedTestServer* proxy_server() { return &proxy_server_; }
private:
net::EmbeddedTestServer proxy_server_;
};
#if defined(OS_MAC) && defined(ADDRESS_SANITIZER)
// TODO(crbug.com/1086872): Disabled due to flakiness on Mac ASAN.
#define MAYBE_SetProxyConfig DISABLED_SetProxyConfig
#else
#define MAYBE_SetProxyConfig SetProxyConfig
#endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy, MAYBE_SetProxyConfig) {
std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig);
proxy_config->proxy_rules().ParseFromString(
proxy_server()->host_port_pair().ToString());
HeadlessBrowserContext* browser_context =
browser()
->CreateBrowserContextBuilder()
.SetProxyConfig(std::move(proxy_config))
.Build();
// Load a page which doesn't actually exist, but for which the our proxy
// returns valid content anyway.
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
EXPECT_THAT(browser()->GetAllBrowserContexts(),
UnorderedElementsAre(browser_context));
EXPECT_THAT(browser_context->GetAllWebContents(),
UnorderedElementsAre(web_contents));
web_contents->Close();
EXPECT_TRUE(browser_context->GetAllWebContents().empty());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WebGLSupported) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().Build();
EXPECT_TRUE(
EvaluateScript(web_contents,
"(document.createElement('canvas').getContext('webgl')"
" instanceof WebGLRenderingContext)")
->GetResult()
->GetValue()
->GetBool());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ClipboardCopyPasteText) {
// Tests copy-pasting text with the clipboard in headless mode.
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ASSERT_TRUE(clipboard);
std::u16string paste_text = u"Clippy!";
for (ui::ClipboardBuffer buffer :
{ui::ClipboardBuffer::kCopyPaste, ui::ClipboardBuffer::kSelection,
ui::ClipboardBuffer::kDrag}) {
if (!ui::Clipboard::IsSupportedClipboardBuffer(buffer))
continue;
{
ui::ScopedClipboardWriter writer(buffer);
writer.WriteText(paste_text);
}
std::u16string copy_text;
clipboard->ReadText(buffer, /* data_dst = */ nullptr, &copy_text);
EXPECT_EQ(paste_text, copy_text);
}
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DefaultSizes) {
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().Build();
HeadlessBrowser::Options::Builder builder;
const HeadlessBrowser::Options kDefaultOptions = builder.Build();
#if !defined(OS_MAC)
// On Mac headless does not override the screen dimensions, so they are
// left with the actual screen values.
EXPECT_EQ(kDefaultOptions.window_size.width(),
EvaluateScript(web_contents, "screen.width")
->GetResult()
->GetValue()
->GetInt());
EXPECT_EQ(kDefaultOptions.window_size.height(),
EvaluateScript(web_contents, "screen.height")
->GetResult()
->GetValue()
->GetInt());
#endif // !defined(OS_MAC)
EXPECT_EQ(kDefaultOptions.window_size.width(),
EvaluateScript(web_contents, "window.innerWidth")
->GetResult()
->GetValue()
->GetInt());
EXPECT_EQ(kDefaultOptions.window_size.height(),
EvaluateScript(web_contents, "window.innerHeight")
->GetResult()
->GetValue()
->GetInt());
}
namespace {
class CookieSetter {
public:
CookieSetter(HeadlessBrowserTest* browser_test,
HeadlessWebContents* web_contents,
std::unique_ptr<network::SetCookieParams> set_cookie_params)
: browser_test_(browser_test),
web_contents_(web_contents),
devtools_client_(HeadlessDevToolsClient::Create()) {
web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
devtools_client_->GetNetwork()->GetExperimental()->SetCookie(
std::move(set_cookie_params),
base::BindOnce(&CookieSetter::OnSetCookieResult,
base::Unretained(this)));
}
~CookieSetter() {
web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
}
void OnSetCookieResult(std::unique_ptr<network::SetCookieResult> result) {
result_ = std::move(result);
browser_test_->FinishAsynchronousTest();
}
std::unique_ptr<network::SetCookieResult> TakeResult() {
return std::move(result_);
}
private:
HeadlessBrowserTest* browser_test_; // Not owned.
HeadlessWebContents* web_contents_; // Not owned.
std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
std::unique_ptr<network::SetCookieResult> result_;
DISALLOW_COPY_AND_ASSIGN(CookieSetter);
};
} // namespace
// TODO(skyostil): This test currently relies on being able to run a shell
// script.
#if defined(OS_POSIX)
class HeadlessBrowserRendererCommandPrefixTest : public HeadlessBrowserTest {
public:
const base::FilePath& launcher_stamp() const { return launcher_stamp_; }
void SetUp() override {
base::CreateTemporaryFile(&launcher_stamp_);
base::ScopedFILE launcher_file =
base::CreateAndOpenTemporaryStream(&launcher_script_);
fprintf(launcher_file.get(), "#!/bin/sh\n");
fprintf(launcher_file.get(), "echo $@ > %s\n",
launcher_stamp_.value().c_str());
fprintf(launcher_file.get(), "exec $@\n");
launcher_file.reset();
#if !defined(OS_FUCHSIA)
base::SetPosixFilePermissions(launcher_script_,
base::FILE_PERMISSION_READ_BY_USER |
base::FILE_PERMISSION_EXECUTE_BY_USER);
#endif // !defined(OS_FUCHSIA)
HeadlessBrowserTest::SetUp();
}
void TearDown() override {
if (!launcher_script_.empty())
base::DeleteFile(launcher_script_);
if (!launcher_stamp_.empty())
base::DeleteFile(launcher_stamp_);
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch("--no-sandbox");
command_line->AppendSwitchASCII("--renderer-cmd-prefix",
launcher_script_.value());
}
private:
base::FilePath launcher_stamp_;
base::FilePath launcher_script_;
};
IN_PROC_BROWSER_TEST_F(HeadlessBrowserRendererCommandPrefixTest, Prefix) {
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(embedded_test_server()->Start());
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
// Make sure the launcher was invoked when starting the renderer.
std::string stamp;
EXPECT_TRUE(base::ReadFileToString(launcher_stamp(), &stamp));
EXPECT_GE(stamp.find("--type=renderer"), 0u);
}
#endif // defined(OS_POSIX)
class CrashReporterTest : public HeadlessBrowserTest,
public HeadlessWebContents::Observer,
inspector::ExperimentalObserver {
public:
CrashReporterTest() {}
~CrashReporterTest() override = default;
void SetUp() override {
base::CreateNewTempDirectory(FILE_PATH_LITERAL("CrashReporterTest"),
&crash_dumps_dir_);
EXPECT_FALSE(options()->enable_crash_reporter);
options()->enable_crash_reporter = true;
options()->crash_dumps_dir = crash_dumps_dir_;
HeadlessBrowserTest::SetUp();
}
void TearDown() override {
base::DeleteFile(crash_dumps_dir_);
}
// HeadlessWebContents::Observer implementation:
void DevToolsTargetReady() override {
EXPECT_TRUE(web_contents_->GetDevToolsTarget());
devtools_client_ = HeadlessDevToolsClient::Create();
web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
devtools_client_->GetInspector()->GetExperimental()->AddObserver(this);
}
// inspector::ExperimentalObserver implementation:
void OnTargetCrashed(const inspector::TargetCrashedParams&) override {
FinishAsynchronousTest();
}
protected:
HeadlessBrowserContext* browser_context_ = nullptr;
HeadlessWebContents* web_contents_ = nullptr;
std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
base::FilePath crash_dumps_dir_;
};
// TODO(skyostil): Minidump generation currently is only supported on Linux and
// Mac.
#if (defined(HEADLESS_USE_BREAKPAD) || defined(OS_MAC)) && \
!defined(ADDRESS_SANITIZER)
#define MAYBE_GenerateMinidump GenerateMinidump
#else
#define MAYBE_GenerateMinidump DISABLED_GenerateMinidump
#endif // defined(HEADLESS_USE_BREAKPAD) || defined(OS_MAC)
IN_PROC_BROWSER_TEST_F(CrashReporterTest, MAYBE_GenerateMinidump) {
content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
// Navigates a tab to chrome://crash and checks that a minidump is generated.
// Note that we only test renderer crashes here -- browser crashes need to be
// tested with a separate harness.
//
// The case where crash reporting is disabled is covered by
// HeadlessCrashObserverTest.
browser_context_ = browser()->CreateBrowserContextBuilder().Build();
web_contents_ = browser_context_->CreateWebContentsBuilder()
.SetInitialURL(GURL(blink::kChromeUICrashURL))
.Build();
web_contents_->AddObserver(this);
RunAsynchronousTest();
// The target has crashed and should no longer be there.
EXPECT_FALSE(web_contents_->GetDevToolsTarget());
// Check that one minidump got created.
{
base::ScopedAllowBlockingForTesting allow_blocking;
#if defined(OS_MAC)
auto database = crashpad::CrashReportDatabase::Initialize(crash_dumps_dir_);
std::vector<crashpad::CrashReportDatabase::Report> reports;
ASSERT_EQ(database->GetPendingReports(&reports),
crashpad::CrashReportDatabase::kNoError);
EXPECT_EQ(reports.size(), 1u);
#else
base::FileEnumerator it(crash_dumps_dir_, /* recursive */ false,
base::FileEnumerator::FILES);
base::FilePath minidump = it.Next();
EXPECT_FALSE(minidump.empty());
EXPECT_EQ(FILE_PATH_LITERAL(".dmp"), minidump.Extension());
EXPECT_TRUE(it.Next().empty());
#endif
}
web_contents_->RemoveObserver(this);
web_contents_->Close();
web_contents_ = nullptr;
browser_context_->Close();
browser_context_ = nullptr;
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, PermissionManagerAlwaysASK) {
GURL url("https://example.com");
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* headless_web_contents =
browser_context->CreateWebContentsBuilder().Build();
EXPECT_TRUE(headless_web_contents);
HeadlessWebContentsImpl* web_contents =
HeadlessWebContentsImpl::From(headless_web_contents);
content::PermissionControllerDelegate* permission_controller_delegate =
web_contents->browser_context()->GetPermissionControllerDelegate();
EXPECT_NE(nullptr, permission_controller_delegate);
// Check that the permission manager returns ASK for a given permission type.
EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
permission_controller_delegate->GetPermissionStatus(
content::PermissionType::NOTIFICATIONS, url, url));
}
namespace {
class TraceHelper : public tracing::ExperimentalObserver {
public:
TraceHelper(HeadlessBrowserTest* browser_test, HeadlessDevToolsTarget* target)
: browser_test_(browser_test),
target_(target),
client_(HeadlessDevToolsClient::Create()),
tracing_data_(std::make_unique<base::ListValue>()) {
EXPECT_FALSE(target_->IsAttached());
target_->AttachClient(client_.get());
EXPECT_TRUE(target_->IsAttached());
client_->GetTracing()->GetExperimental()->AddObserver(this);
client_->GetTracing()->GetExperimental()->Start(
tracing::StartParams::Builder().Build(),
base::BindOnce(&TraceHelper::OnTracingStarted, base::Unretained(this)));
}
~TraceHelper() override {
target_->DetachClient(client_.get());
EXPECT_FALSE(target_->IsAttached());
}
std::unique_ptr<base::ListValue> TakeTracingData() {
return std::move(tracing_data_);
}
private:
void OnTracingStarted(std::unique_ptr<tracing::StartResult>) {
// We don't need the callback from End, but the OnTracingComplete event.
client_->GetTracing()->GetExperimental()->End(
tracing::EndParams::Builder().Build());
}
// tracing::ExperimentalObserver implementation:
void OnDataCollected(const tracing::DataCollectedParams& params) override {
for (const auto& value : *params.GetValue()) {
tracing_data_->Append(value->CreateDeepCopy());
}
}
void OnTracingComplete(
const tracing::TracingCompleteParams& params) override {
browser_test_->FinishAsynchronousTest();
}
HeadlessBrowserTest* browser_test_; // Not owned.
HeadlessDevToolsTarget* target_; // Not owned.
std::unique_ptr<HeadlessDevToolsClient> client_;
std::unique_ptr<base::ListValue> tracing_data_;
DISALLOW_COPY_AND_ASSIGN(TraceHelper);
};
} // namespace
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, TraceUsingBrowserDevToolsTarget) {
HeadlessDevToolsTarget* target = browser()->GetDevToolsTarget();
EXPECT_NE(nullptr, target);
TraceHelper helper(this, target);
RunAsynchronousTest();
std::unique_ptr<base::ListValue> tracing_data = helper.TakeTracingData();
EXPECT_TRUE(tracing_data);
EXPECT_LT(0u, tracing_data->GetSize());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, WindowPrint) {
EXPECT_TRUE(embedded_test_server()->Start());
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
EXPECT_FALSE(
EvaluateScript(web_contents, "window.print()")->HasExceptionDetails());
}
class HeadlessBrowserAllowInsecureLocalhostTest : public HeadlessBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kAllowInsecureLocalhost);
}
};
IN_PROC_BROWSER_TEST_F(HeadlessBrowserAllowInsecureLocalhostTest,
AllowInsecureLocalhostFlag) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
https_server.ServeFilesFromSourceDirectory("headless/test/data");
ASSERT_TRUE(https_server.Start());
GURL test_url = https_server.GetURL("/hello.html");
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContentsImpl* web_contents =
HeadlessWebContentsImpl::From(browser_context->CreateWebContentsBuilder()
.SetInitialURL(test_url)
.Build());
// If the certificate fails to validate, this should fail.
EXPECT_TRUE(WaitForLoad(web_contents));
}
class HeadlessBrowserTestAppendCommandLineFlags : public HeadlessBrowserTest {
public:
HeadlessBrowserTestAppendCommandLineFlags() {
options()->append_command_line_flags_callback = base::BindRepeating(
&HeadlessBrowserTestAppendCommandLineFlags::AppendCommandLineFlags,
base::Unretained(this));
}
void AppendCommandLineFlags(base::CommandLine* command_line,
HeadlessBrowserContext* child_browser_context,
const std::string& child_process_type,
int child_process_id) {
if (child_process_type != "renderer")
return;
callback_was_run_ = true;
EXPECT_LE(0, child_process_id);
EXPECT_NE(nullptr, command_line);
EXPECT_NE(nullptr, child_browser_context);
}
protected:
bool callback_was_run_ = false;
};
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestAppendCommandLineFlags,
AppendChildProcessCommandLineFlags) {
// Create a new renderer process, and verify that callback was executed.
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(GURL("about:blank"))
.Build();
EXPECT_TRUE(callback_was_run_);
// Used only for lifetime.
(void)web_contents;
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ServerWantsClientCertificate) {
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
net::SpawnedTestServer server(
net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
base::FilePath(FILE_PATH_LITERAL("headless/test/data")));
EXPECT_TRUE(server.Start());
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(server.GetURL("/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, AIAFetching) {
net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS);
net::EmbeddedTestServer::ServerCertificateConfig cert_config;
cert_config.intermediate = net::EmbeddedTestServer::IntermediateType::kByAIA;
server.SetSSLConfig(cert_config);
server.AddDefaultHandlers(base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
ASSERT_TRUE(server.Start());
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
browser()->SetDefaultBrowserContext(browser_context);
GURL url = server.GetURL("/defaultresponse");
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build();
EXPECT_TRUE(WaitForLoad(web_contents));
content::NavigationEntry* last_entry =
HeadlessWebContentsImpl::From(web_contents)
->web_contents()
->GetController()
.GetLastCommittedEntry();
EXPECT_FALSE(net::IsCertStatusError(last_entry->GetSSL().cert_status));
EXPECT_EQ(url, last_entry->GetURL());
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, BadgingAPI) {
EXPECT_TRUE(embedded_test_server()->Start());
HeadlessBrowserContext* browser_context =
browser()->CreateBrowserContextBuilder().Build();
GURL url = embedded_test_server()->GetURL("/badging_api.html");
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build();
EXPECT_TRUE(WaitForLoad(web_contents));
}
} // namespace headless