1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "build/build_config.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/browser/permission_controller_delegate.h"
18 #include "content/public/browser/permission_type.h"
19 #include "content/public/browser/ssl_status.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/test/browser_test.h"
24 #include "content/public/test/no_renderer_crashes_assertion.h"
25 #include "headless/lib/browser/headless_browser_context_impl.h"
26 #include "headless/lib/browser/headless_web_contents_impl.h"
27 #include "headless/lib/headless_macros.h"
28 #include "headless/public/devtools/domains/inspector.h"
29 #include "headless/public/devtools/domains/network.h"
30 #include "headless/public/devtools/domains/page.h"
31 #include "headless/public/devtools/domains/tracing.h"
32 #include "headless/public/headless_browser.h"
33 #include "headless/public/headless_devtools_client.h"
34 #include "headless/public/headless_devtools_target.h"
35 #include "headless/public/headless_web_contents.h"
36 #include "headless/test/headless_browser_test.h"
37 #include "net/cert/cert_status_flags.h"
38 #include "net/test/spawned_test_server/spawned_test_server.h"
39 #include "testing/gmock/include/gmock/gmock.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "ui/base/clipboard/clipboard.h"
42 #include "ui/base/clipboard/scoped_clipboard_writer.h"
43 #include "ui/gfx/geometry/size.h"
44
45 #if defined(OS_MACOSX)
46 #include "third_party/crashpad/crashpad/client/crash_report_database.h"
47 #endif
48
49 using testing::UnorderedElementsAre;
50
51 namespace headless {
52
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDestroyBrowserContext)53 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyBrowserContext) {
54 HeadlessBrowserContext* browser_context =
55 browser()->CreateBrowserContextBuilder().Build();
56
57 EXPECT_THAT(browser()->GetAllBrowserContexts(),
58 UnorderedElementsAre(browser_context));
59
60 browser_context->Close();
61
62 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
63 }
64
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDoNotDestroyBrowserContext)65 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
66 CreateAndDoNotDestroyBrowserContext) {
67 HeadlessBrowserContext* browser_context =
68 browser()->CreateBrowserContextBuilder().Build();
69
70 EXPECT_THAT(browser()->GetAllBrowserContexts(),
71 UnorderedElementsAre(browser_context));
72
73 // We check that HeadlessBrowser correctly handles non-closed BrowserContexts.
74 // We can rely on Chromium DCHECKs to capture this.
75 }
76
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDestroyWebContents)77 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) {
78 HeadlessBrowserContext* browser_context =
79 browser()->CreateBrowserContextBuilder().Build();
80
81 HeadlessWebContents* web_contents =
82 browser_context->CreateWebContentsBuilder().Build();
83 EXPECT_TRUE(web_contents);
84
85 EXPECT_THAT(browser()->GetAllBrowserContexts(),
86 UnorderedElementsAre(browser_context));
87 EXPECT_THAT(browser_context->GetAllWebContents(),
88 UnorderedElementsAre(web_contents));
89
90 // TODO(skyostil): Verify viewport dimensions once we can.
91
92 web_contents->Close();
93
94 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
95
96 browser_context->Close();
97
98 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
99 }
100
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,WebContentsAreDestroyedWithContext)101 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
102 WebContentsAreDestroyedWithContext) {
103 HeadlessBrowserContext* browser_context =
104 browser()->CreateBrowserContextBuilder().Build();
105
106 HeadlessWebContents* web_contents =
107 browser_context->CreateWebContentsBuilder().Build();
108 EXPECT_TRUE(web_contents);
109
110 EXPECT_THAT(browser()->GetAllBrowserContexts(),
111 UnorderedElementsAre(browser_context));
112 EXPECT_THAT(browser_context->GetAllWebContents(),
113 UnorderedElementsAre(web_contents));
114
115 browser_context->Close();
116
117 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
118
119 // If WebContents are not destroyed, Chromium DCHECKs will capture this.
120 }
121
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateAndDoNotDestroyWebContents)122 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDoNotDestroyWebContents) {
123 HeadlessBrowserContext* browser_context =
124 browser()->CreateBrowserContextBuilder().Build();
125
126 HeadlessWebContents* web_contents =
127 browser_context->CreateWebContentsBuilder().Build();
128 EXPECT_TRUE(web_contents);
129
130 EXPECT_THAT(browser()->GetAllBrowserContexts(),
131 UnorderedElementsAre(browser_context));
132 EXPECT_THAT(browser_context->GetAllWebContents(),
133 UnorderedElementsAre(web_contents));
134
135 // If WebContents are not destroyed, Chromium DCHECKs will capture this.
136 }
137
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,DestroyAndCreateTwoWebContents)138 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, DestroyAndCreateTwoWebContents) {
139 HeadlessBrowserContext* browser_context1 =
140 browser()->CreateBrowserContextBuilder().Build();
141 EXPECT_TRUE(browser_context1);
142 HeadlessWebContents* web_contents1 =
143 browser_context1->CreateWebContentsBuilder().Build();
144 EXPECT_TRUE(web_contents1);
145
146 EXPECT_THAT(browser()->GetAllBrowserContexts(),
147 UnorderedElementsAre(browser_context1));
148 EXPECT_THAT(browser_context1->GetAllWebContents(),
149 UnorderedElementsAre(web_contents1));
150
151 HeadlessBrowserContext* browser_context2 =
152 browser()->CreateBrowserContextBuilder().Build();
153 EXPECT_TRUE(browser_context2);
154 HeadlessWebContents* web_contents2 =
155 browser_context2->CreateWebContentsBuilder().Build();
156 EXPECT_TRUE(web_contents2);
157
158 EXPECT_THAT(browser()->GetAllBrowserContexts(),
159 UnorderedElementsAre(browser_context1, browser_context2));
160 EXPECT_THAT(browser_context1->GetAllWebContents(),
161 UnorderedElementsAre(web_contents1));
162 EXPECT_THAT(browser_context2->GetAllWebContents(),
163 UnorderedElementsAre(web_contents2));
164
165 browser_context1->Close();
166
167 EXPECT_THAT(browser()->GetAllBrowserContexts(),
168 UnorderedElementsAre(browser_context2));
169 EXPECT_THAT(browser_context2->GetAllWebContents(),
170 UnorderedElementsAre(web_contents2));
171
172 browser_context2->Close();
173
174 EXPECT_TRUE(browser()->GetAllBrowserContexts().empty());
175 }
176
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,CreateWithBadURL)177 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateWithBadURL) {
178 GURL bad_url("not_valid");
179
180 HeadlessBrowserContext* browser_context =
181 browser()->CreateBrowserContextBuilder().Build();
182
183 HeadlessWebContents* web_contents =
184 browser_context->CreateWebContentsBuilder()
185 .SetInitialURL(bad_url)
186 .Build();
187
188 EXPECT_FALSE(web_contents);
189 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
190 }
191
192 class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest {
193 public:
HeadlessBrowserTestWithProxy()194 HeadlessBrowserTestWithProxy()
195 : proxy_server_(net::SpawnedTestServer::TYPE_HTTP,
196 base::FilePath(FILE_PATH_LITERAL("headless/test/data"))) {
197 }
198
SetUp()199 void SetUp() override {
200 ASSERT_TRUE(proxy_server_.Start());
201 HeadlessBrowserTest::SetUp();
202 }
203
TearDown()204 void TearDown() override {
205 proxy_server_.Stop();
206 HeadlessBrowserTest::TearDown();
207 }
208
proxy_server()209 net::SpawnedTestServer* proxy_server() { return &proxy_server_; }
210
211 private:
212 net::SpawnedTestServer proxy_server_;
213 };
214
215 #if defined(OS_WIN)
216 // TODO(crbug.com/1045971): Disabled due to flakiness.
217 #define MAYBE_SetProxyConfig DISABLED_SetProxyConfig
218 #else
219 #define MAYBE_SetProxyConfig SetProxyConfig
220 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy,MAYBE_SetProxyConfig)221 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy, MAYBE_SetProxyConfig) {
222 std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig);
223 proxy_config->proxy_rules().ParseFromString(
224 proxy_server()->host_port_pair().ToString());
225 HeadlessBrowserContext* browser_context =
226 browser()
227 ->CreateBrowserContextBuilder()
228 .SetProxyConfig(std::move(proxy_config))
229 .Build();
230
231 // Load a page which doesn't actually exist, but for which the our proxy
232 // returns valid content anyway.
233 HeadlessWebContents* web_contents =
234 browser_context->CreateWebContentsBuilder()
235 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
236 .Build();
237 EXPECT_TRUE(WaitForLoad(web_contents));
238 EXPECT_THAT(browser()->GetAllBrowserContexts(),
239 UnorderedElementsAre(browser_context));
240 EXPECT_THAT(browser_context->GetAllWebContents(),
241 UnorderedElementsAre(web_contents));
242 web_contents->Close();
243 EXPECT_TRUE(browser_context->GetAllWebContents().empty());
244 }
245
246 // TODO(crbug.com/867447): Flaky on Windows 10 debug.
247 #if defined(OS_WIN) && !defined(NDEBUG)
248 #define MAYBE_WebGLSupported DISABLED_WebGLSupported
249 #else
250 #define MAYBE_WebGLSupported WebGLSupported
251 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,MAYBE_WebGLSupported)252 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, MAYBE_WebGLSupported) {
253 HeadlessBrowserContext* browser_context =
254 browser()->CreateBrowserContextBuilder().Build();
255
256 HeadlessWebContents* web_contents =
257 browser_context->CreateWebContentsBuilder().Build();
258
259 EXPECT_TRUE(
260 EvaluateScript(web_contents,
261 "(document.createElement('canvas').getContext('webgl')"
262 " instanceof WebGLRenderingContext)")
263 ->GetResult()
264 ->GetValue()
265 ->GetBool());
266 }
267
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,ClipboardCopyPasteText)268 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ClipboardCopyPasteText) {
269 // Tests copy-pasting text with the clipboard in headless mode.
270 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
271 ASSERT_TRUE(clipboard);
272 base::string16 paste_text = base::ASCIIToUTF16("Clippy!");
273 for (ui::ClipboardBuffer buffer :
274 {ui::ClipboardBuffer::kCopyPaste, ui::ClipboardBuffer::kSelection,
275 ui::ClipboardBuffer::kDrag}) {
276 if (!ui::Clipboard::IsSupportedClipboardBuffer(buffer))
277 continue;
278 {
279 ui::ScopedClipboardWriter writer(buffer);
280 writer.WriteText(paste_text);
281 }
282 base::string16 copy_text;
283 clipboard->ReadText(buffer, ©_text);
284 EXPECT_EQ(paste_text, copy_text);
285 }
286 }
287
288 #if defined(OS_WIN)
289 // TODO(crbug.com/1045971): Disabled due to flakiness.
290 #define MAYBE_DefaultSizes DISABLED_DefaultSizes
291 #else
292 #define MAYBE_DefaultSizes DefaultSizes
293 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,MAYBE_DefaultSizes)294 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, MAYBE_DefaultSizes) {
295 HeadlessBrowserContext* browser_context =
296 browser()->CreateBrowserContextBuilder().Build();
297
298 HeadlessWebContents* web_contents =
299 browser_context->CreateWebContentsBuilder().Build();
300
301 HeadlessBrowser::Options::Builder builder;
302 const HeadlessBrowser::Options kDefaultOptions = builder.Build();
303
304 #if !defined(OS_MACOSX)
305 // On Mac headless does not override the screen dimensions, so they are
306 // left with the actual screen values.
307 EXPECT_EQ(kDefaultOptions.window_size.width(),
308 EvaluateScript(web_contents, "screen.width")
309 ->GetResult()
310 ->GetValue()
311 ->GetInt());
312 EXPECT_EQ(kDefaultOptions.window_size.height(),
313 EvaluateScript(web_contents, "screen.height")
314 ->GetResult()
315 ->GetValue()
316 ->GetInt());
317 #endif // !defined(OS_MACOSX)
318 EXPECT_EQ(kDefaultOptions.window_size.width(),
319 EvaluateScript(web_contents, "window.innerWidth")
320 ->GetResult()
321 ->GetValue()
322 ->GetInt());
323 EXPECT_EQ(kDefaultOptions.window_size.height(),
324 EvaluateScript(web_contents, "window.innerHeight")
325 ->GetResult()
326 ->GetValue()
327 ->GetInt());
328 }
329
330 namespace {
331
332 class CookieSetter {
333 public:
CookieSetter(HeadlessBrowserTest * browser_test,HeadlessWebContents * web_contents,std::unique_ptr<network::SetCookieParams> set_cookie_params)334 CookieSetter(HeadlessBrowserTest* browser_test,
335 HeadlessWebContents* web_contents,
336 std::unique_ptr<network::SetCookieParams> set_cookie_params)
337 : browser_test_(browser_test),
338 web_contents_(web_contents),
339 devtools_client_(HeadlessDevToolsClient::Create()) {
340 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
341 devtools_client_->GetNetwork()->GetExperimental()->SetCookie(
342 std::move(set_cookie_params),
343 base::BindOnce(&CookieSetter::OnSetCookieResult,
344 base::Unretained(this)));
345 }
346
~CookieSetter()347 ~CookieSetter() {
348 web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
349 }
350
OnSetCookieResult(std::unique_ptr<network::SetCookieResult> result)351 void OnSetCookieResult(std::unique_ptr<network::SetCookieResult> result) {
352 result_ = std::move(result);
353 browser_test_->FinishAsynchronousTest();
354 }
355
TakeResult()356 std::unique_ptr<network::SetCookieResult> TakeResult() {
357 return std::move(result_);
358 }
359
360 private:
361 HeadlessBrowserTest* browser_test_; // Not owned.
362 HeadlessWebContents* web_contents_; // Not owned.
363 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
364
365 std::unique_ptr<network::SetCookieResult> result_;
366
367 DISALLOW_COPY_AND_ASSIGN(CookieSetter);
368 };
369
370 } // namespace
371
372 // TODO(skyostil): This test currently relies on being able to run a shell
373 // script.
374 #if defined(OS_POSIX)
375 class HeadlessBrowserRendererCommandPrefixTest : public HeadlessBrowserTest {
376 public:
launcher_stamp() const377 const base::FilePath& launcher_stamp() const { return launcher_stamp_; }
378
SetUp()379 void SetUp() override {
380 base::ThreadRestrictions::SetIOAllowed(true);
381 base::CreateTemporaryFile(&launcher_stamp_);
382
383 FILE* launcher_file = base::CreateAndOpenTemporaryFile(&launcher_script_);
384 fprintf(launcher_file, "#!/bin/sh\n");
385 fprintf(launcher_file, "echo $@ > %s\n", launcher_stamp_.value().c_str());
386 fprintf(launcher_file, "exec $@\n");
387 fclose(launcher_file);
388 #if !defined(OS_FUCHSIA)
389 base::SetPosixFilePermissions(launcher_script_,
390 base::FILE_PERMISSION_READ_BY_USER |
391 base::FILE_PERMISSION_EXECUTE_BY_USER);
392 #endif // !defined(OS_FUCHSIA)
393
394 HeadlessBrowserTest::SetUp();
395 }
396
TearDown()397 void TearDown() override {
398 if (!launcher_script_.empty())
399 base::DeleteFile(launcher_script_, false);
400 if (!launcher_stamp_.empty())
401 base::DeleteFile(launcher_stamp_, false);
402 }
403
SetUpCommandLine(base::CommandLine * command_line)404 void SetUpCommandLine(base::CommandLine* command_line) override {
405 command_line->AppendSwitch("--no-sandbox");
406 command_line->AppendSwitchASCII("--renderer-cmd-prefix",
407 launcher_script_.value());
408 }
409
410 private:
411 base::FilePath launcher_stamp_;
412 base::FilePath launcher_script_;
413 };
414
IN_PROC_BROWSER_TEST_F(HeadlessBrowserRendererCommandPrefixTest,Prefix)415 IN_PROC_BROWSER_TEST_F(HeadlessBrowserRendererCommandPrefixTest, Prefix) {
416 base::ThreadRestrictions::SetIOAllowed(true);
417 EXPECT_TRUE(embedded_test_server()->Start());
418
419 HeadlessBrowserContext* browser_context =
420 browser()->CreateBrowserContextBuilder().Build();
421
422 HeadlessWebContents* web_contents =
423 browser_context->CreateWebContentsBuilder()
424 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
425 .Build();
426 EXPECT_TRUE(WaitForLoad(web_contents));
427
428 // Make sure the launcher was invoked when starting the renderer.
429 std::string stamp;
430 EXPECT_TRUE(base::ReadFileToString(launcher_stamp(), &stamp));
431 EXPECT_GE(stamp.find("--type=renderer"), 0u);
432 }
433 #endif // defined(OS_POSIX)
434
435 class CrashReporterTest : public HeadlessBrowserTest,
436 public HeadlessWebContents::Observer,
437 inspector::ExperimentalObserver {
438 public:
CrashReporterTest()439 CrashReporterTest() {}
440 ~CrashReporterTest() override = default;
441
SetUp()442 void SetUp() override {
443 base::ThreadRestrictions::SetIOAllowed(true);
444 base::CreateNewTempDirectory(FILE_PATH_LITERAL("CrashReporterTest"),
445 &crash_dumps_dir_);
446 EXPECT_FALSE(options()->enable_crash_reporter);
447 options()->enable_crash_reporter = true;
448 options()->crash_dumps_dir = crash_dumps_dir_;
449 HeadlessBrowserTest::SetUp();
450 }
451
TearDown()452 void TearDown() override {
453 base::ThreadRestrictions::SetIOAllowed(true);
454 base::DeleteFile(crash_dumps_dir_, /* recursive */ false);
455 }
456
457 // HeadlessWebContents::Observer implementation:
DevToolsTargetReady()458 void DevToolsTargetReady() override {
459 EXPECT_TRUE(web_contents_->GetDevToolsTarget());
460 devtools_client_ = HeadlessDevToolsClient::Create();
461 web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
462 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this);
463 }
464
465 // inspector::ExperimentalObserver implementation:
OnTargetCrashed(const inspector::TargetCrashedParams &)466 void OnTargetCrashed(const inspector::TargetCrashedParams&) override {
467 FinishAsynchronousTest();
468 }
469
470 protected:
471 HeadlessBrowserContext* browser_context_ = nullptr;
472 HeadlessWebContents* web_contents_ = nullptr;
473 std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
474 base::FilePath crash_dumps_dir_;
475 };
476
477 // TODO(skyostil): Minidump generation currently is only supported on Linux and
478 // Mac.
479 #if (defined(HEADLESS_USE_BREAKPAD) || defined(OS_MACOSX)) && \
480 !defined(ADDRESS_SANITIZER)
481 #define MAYBE_GenerateMinidump GenerateMinidump
482 #else
483 #define MAYBE_GenerateMinidump DISABLED_GenerateMinidump
484 #endif // defined(HEADLESS_USE_BREAKPAD) || defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(CrashReporterTest,MAYBE_GenerateMinidump)485 IN_PROC_BROWSER_TEST_F(CrashReporterTest, MAYBE_GenerateMinidump) {
486 content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
487
488 // Navigates a tab to chrome://crash and checks that a minidump is generated.
489 // Note that we only test renderer crashes here -- browser crashes need to be
490 // tested with a separate harness.
491 //
492 // The case where crash reporting is disabled is covered by
493 // HeadlessCrashObserverTest.
494 browser_context_ = browser()->CreateBrowserContextBuilder().Build();
495
496 web_contents_ = browser_context_->CreateWebContentsBuilder()
497 .SetInitialURL(GURL(content::kChromeUICrashURL))
498 .Build();
499
500 web_contents_->AddObserver(this);
501 RunAsynchronousTest();
502
503 // The target has crashed and should no longer be there.
504 EXPECT_FALSE(web_contents_->GetDevToolsTarget());
505
506 // Check that one minidump got created.
507 {
508 base::ThreadRestrictions::SetIOAllowed(true);
509
510 #if defined(OS_MACOSX)
511 auto database = crashpad::CrashReportDatabase::Initialize(crash_dumps_dir_);
512 std::vector<crashpad::CrashReportDatabase::Report> reports;
513 ASSERT_EQ(database->GetPendingReports(&reports),
514 crashpad::CrashReportDatabase::kNoError);
515 EXPECT_EQ(reports.size(), 1u);
516 #else
517 base::FileEnumerator it(crash_dumps_dir_, /* recursive */ false,
518 base::FileEnumerator::FILES);
519 base::FilePath minidump = it.Next();
520 EXPECT_FALSE(minidump.empty());
521 EXPECT_EQ(FILE_PATH_LITERAL(".dmp"), minidump.Extension());
522 EXPECT_TRUE(it.Next().empty());
523 #endif
524 }
525
526 web_contents_->RemoveObserver(this);
527 web_contents_->Close();
528 web_contents_ = nullptr;
529
530 browser_context_->Close();
531 browser_context_ = nullptr;
532 }
533
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,PermissionManagerAlwaysASK)534 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, PermissionManagerAlwaysASK) {
535 GURL url("https://example.com");
536
537 HeadlessBrowserContext* browser_context =
538 browser()->CreateBrowserContextBuilder().Build();
539
540 HeadlessWebContents* headless_web_contents =
541 browser_context->CreateWebContentsBuilder().Build();
542 EXPECT_TRUE(headless_web_contents);
543
544 HeadlessWebContentsImpl* web_contents =
545 HeadlessWebContentsImpl::From(headless_web_contents);
546
547 content::PermissionControllerDelegate* permission_controller_delegate =
548 web_contents->browser_context()->GetPermissionControllerDelegate();
549 EXPECT_NE(nullptr, permission_controller_delegate);
550
551 // Check that the permission manager returns ASK for a given permission type.
552 EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
553 permission_controller_delegate->GetPermissionStatus(
554 content::PermissionType::NOTIFICATIONS, url, url));
555 }
556
557 namespace {
558
559 class TraceHelper : public tracing::ExperimentalObserver {
560 public:
TraceHelper(HeadlessBrowserTest * browser_test,HeadlessDevToolsTarget * target)561 TraceHelper(HeadlessBrowserTest* browser_test, HeadlessDevToolsTarget* target)
562 : browser_test_(browser_test),
563 target_(target),
564 client_(HeadlessDevToolsClient::Create()),
565 tracing_data_(std::make_unique<base::ListValue>()) {
566 EXPECT_FALSE(target_->IsAttached());
567 target_->AttachClient(client_.get());
568 EXPECT_TRUE(target_->IsAttached());
569
570 client_->GetTracing()->GetExperimental()->AddObserver(this);
571
572 client_->GetTracing()->GetExperimental()->Start(
573 tracing::StartParams::Builder().Build(),
574 base::BindOnce(&TraceHelper::OnTracingStarted, base::Unretained(this)));
575 }
576
~TraceHelper()577 ~TraceHelper() override {
578 target_->DetachClient(client_.get());
579 EXPECT_FALSE(target_->IsAttached());
580 }
581
TakeTracingData()582 std::unique_ptr<base::ListValue> TakeTracingData() {
583 return std::move(tracing_data_);
584 }
585
586 private:
OnTracingStarted(std::unique_ptr<tracing::StartResult>)587 void OnTracingStarted(std::unique_ptr<tracing::StartResult>) {
588 // We don't need the callback from End, but the OnTracingComplete event.
589 client_->GetTracing()->GetExperimental()->End(
590 tracing::EndParams::Builder().Build());
591 }
592
593 // tracing::ExperimentalObserver implementation:
OnDataCollected(const tracing::DataCollectedParams & params)594 void OnDataCollected(const tracing::DataCollectedParams& params) override {
595 for (const auto& value : *params.GetValue()) {
596 tracing_data_->Append(value->CreateDeepCopy());
597 }
598 }
599
OnTracingComplete(const tracing::TracingCompleteParams & params)600 void OnTracingComplete(
601 const tracing::TracingCompleteParams& params) override {
602 browser_test_->FinishAsynchronousTest();
603 }
604
605 HeadlessBrowserTest* browser_test_; // Not owned.
606 HeadlessDevToolsTarget* target_; // Not owned.
607 std::unique_ptr<HeadlessDevToolsClient> client_;
608
609 std::unique_ptr<base::ListValue> tracing_data_;
610
611 DISALLOW_COPY_AND_ASSIGN(TraceHelper);
612 };
613
614 } // namespace
615
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,TraceUsingBrowserDevToolsTarget)616 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, TraceUsingBrowserDevToolsTarget) {
617 HeadlessDevToolsTarget* target = browser()->GetDevToolsTarget();
618 EXPECT_NE(nullptr, target);
619
620 TraceHelper helper(this, target);
621 RunAsynchronousTest();
622
623 std::unique_ptr<base::ListValue> tracing_data = helper.TakeTracingData();
624 EXPECT_TRUE(tracing_data);
625 EXPECT_LT(0u, tracing_data->GetSize());
626 }
627
628 #if defined(OS_WIN)
629 // TODO(crbug.com/1045971): Disabled due to flakiness.
630 #define MAYBE_WindowPrint DISABLED_WindowPrint
631 #else
632 #define MAYBE_WindowPrint WindowPrint
633 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,MAYBE_WindowPrint)634 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, MAYBE_WindowPrint) {
635 EXPECT_TRUE(embedded_test_server()->Start());
636
637 HeadlessBrowserContext* browser_context =
638 browser()->CreateBrowserContextBuilder().Build();
639
640 HeadlessWebContents* web_contents =
641 browser_context->CreateWebContentsBuilder()
642 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
643 .Build();
644 EXPECT_TRUE(WaitForLoad(web_contents));
645 EXPECT_FALSE(
646 EvaluateScript(web_contents, "window.print()")->HasExceptionDetails());
647 }
648
649 class HeadlessBrowserAllowInsecureLocalhostTest : public HeadlessBrowserTest {
650 public:
SetUpCommandLine(base::CommandLine * command_line)651 void SetUpCommandLine(base::CommandLine* command_line) override {
652 command_line->AppendSwitch(switches::kAllowInsecureLocalhost);
653 }
654 };
655
656 #if defined(OS_WIN)
657 // TODO(crbug.com/1045971): Disabled due to flakiness.
658 #define MAYBE_AllowInsecureLocalhostFlag DISABLED_AllowInsecureLocalhostFlag
659 #else
660 #define MAYBE_AllowInsecureLocalhostFlag AllowInsecureLocalhostFlag
661 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserAllowInsecureLocalhostTest,MAYBE_AllowInsecureLocalhostFlag)662 IN_PROC_BROWSER_TEST_F(HeadlessBrowserAllowInsecureLocalhostTest,
663 MAYBE_AllowInsecureLocalhostFlag) {
664 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
665 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
666 https_server.ServeFilesFromSourceDirectory("headless/test/data");
667 ASSERT_TRUE(https_server.Start());
668 GURL test_url = https_server.GetURL("/hello.html");
669
670 HeadlessBrowserContext* browser_context =
671 browser()->CreateBrowserContextBuilder().Build();
672
673 HeadlessWebContentsImpl* web_contents =
674 HeadlessWebContentsImpl::From(browser_context->CreateWebContentsBuilder()
675 .SetInitialURL(test_url)
676 .Build());
677
678 // If the certificate fails to validate, this should fail.
679 EXPECT_TRUE(WaitForLoad(web_contents));
680 }
681
682 class HeadlessBrowserTestAppendCommandLineFlags : public HeadlessBrowserTest {
683 public:
HeadlessBrowserTestAppendCommandLineFlags()684 HeadlessBrowserTestAppendCommandLineFlags() {
685 options()->append_command_line_flags_callback = base::BindRepeating(
686 &HeadlessBrowserTestAppendCommandLineFlags::AppendCommandLineFlags,
687 base::Unretained(this));
688 }
689
AppendCommandLineFlags(base::CommandLine * command_line,HeadlessBrowserContext * child_browser_context,const std::string & child_process_type,int child_process_id)690 void AppendCommandLineFlags(base::CommandLine* command_line,
691 HeadlessBrowserContext* child_browser_context,
692 const std::string& child_process_type,
693 int child_process_id) {
694 if (child_process_type != "renderer")
695 return;
696
697 callback_was_run_ = true;
698 EXPECT_LE(0, child_process_id);
699 EXPECT_NE(nullptr, command_line);
700 EXPECT_NE(nullptr, child_browser_context);
701 }
702
703 protected:
704 bool callback_was_run_ = false;
705 };
706
707 #if defined(OS_WIN)
708 // Flaky on Win ASAN. See https://crbug.com/884095.
709 #define MAYBE_AppendChildProcessCommandLineFlags \
710 DISABLED_AppendChildProcessCommandLineFlags
711 #else
712 #define MAYBE_AppendChildProcessCommandLineFlags \
713 AppendChildProcessCommandLineFlags
714 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestAppendCommandLineFlags,MAYBE_AppendChildProcessCommandLineFlags)715 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestAppendCommandLineFlags,
716 MAYBE_AppendChildProcessCommandLineFlags) {
717 // Create a new renderer process, and verify that callback was executed.
718 HeadlessBrowserContext* browser_context =
719 browser()->CreateBrowserContextBuilder().Build();
720 HeadlessWebContents* web_contents =
721 browser_context->CreateWebContentsBuilder()
722 .SetInitialURL(GURL("about:blank"))
723 .Build();
724
725 EXPECT_TRUE(callback_was_run_);
726
727 // Used only for lifetime.
728 (void)web_contents;
729 }
730
731 #if defined(OS_WIN)
732 // TODO(crbug.com/1045971): Disabled due to flakiness.
733 #define MAYBE_ServerWantsClientCertificate DISABLED_ServerWantsClientCertificate
734 #else
735 #define MAYBE_ServerWantsClientCertificate ServerWantsClientCertificate
736 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,MAYBE_ServerWantsClientCertificate)737 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,
738 MAYBE_ServerWantsClientCertificate) {
739 net::SpawnedTestServer::SSLOptions ssl_options;
740 ssl_options.request_client_certificate = true;
741
742 net::SpawnedTestServer server(
743 net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
744 base::FilePath(FILE_PATH_LITERAL("headless/test/data")));
745 EXPECT_TRUE(server.Start());
746
747 HeadlessBrowserContext* browser_context =
748 browser()->CreateBrowserContextBuilder().Build();
749
750 HeadlessWebContents* web_contents =
751 browser_context->CreateWebContentsBuilder()
752 .SetInitialURL(server.GetURL("/hello.html"))
753 .Build();
754 EXPECT_TRUE(WaitForLoad(web_contents));
755 }
756
757 #if defined(OS_WIN)
758 // TODO(crbug.com/1045971): Disabled due to flakiness.
759 #define MAYBE_AIAFetching DISABLED_AIAFetching
760 #else
761 #define MAYBE_AIAFetching AIAFetching
762 #endif
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest,MAYBE_AIAFetching)763 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, MAYBE_AIAFetching) {
764 net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS);
765 server.SetSSLConfig(net::EmbeddedTestServer::CERT_AUTO_AIA_INTERMEDIATE);
766 server.AddDefaultHandlers(base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
767 ASSERT_TRUE(server.Start());
768
769 HeadlessBrowserContext* browser_context =
770 browser()->CreateBrowserContextBuilder().Build();
771 browser()->SetDefaultBrowserContext(browser_context);
772
773 GURL url = server.GetURL("/defaultresponse");
774 HeadlessWebContents* web_contents =
775 browser_context->CreateWebContentsBuilder().SetInitialURL(url).Build();
776 EXPECT_TRUE(WaitForLoad(web_contents));
777 content::NavigationEntry* last_entry =
778 HeadlessWebContentsImpl::From(web_contents)
779 ->web_contents()
780 ->GetController()
781 .GetLastCommittedEntry();
782 EXPECT_FALSE(net::IsCertStatusError(last_entry->GetSSL().cert_status));
783 EXPECT_EQ(url, last_entry->GetURL());
784 }
785
786 } // namespace headless
787