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/base_paths.h" 8 #include "base/bind.h" 9 #include "base/files/file_util.h" 10 #include "base/json/json_reader.h" 11 #include "base/json/json_writer.h" 12 #include "base/path_service.h" 13 #include "base/run_loop.h" 14 #include "base/strings/string_util.h" 15 #include "base/threading/thread_restrictions.h" 16 #include "build/build_config.h" 17 #include "content/public/browser/render_widget_host_view.h" 18 #include "content/public/browser/web_contents.h" 19 #include "content/public/common/url_constants.h" 20 #include "content/public/test/browser_test.h" 21 #include "content/public/test/no_renderer_crashes_assertion.h" 22 #include "headless/lib/browser/headless_web_contents_impl.h" 23 #include "headless/public/devtools/domains/browser.h" 24 #include "headless/public/devtools/domains/dom.h" 25 #include "headless/public/devtools/domains/dom_snapshot.h" 26 #include "headless/public/devtools/domains/emulation.h" 27 #include "headless/public/devtools/domains/inspector.h" 28 #include "headless/public/devtools/domains/network.h" 29 #include "headless/public/devtools/domains/page.h" 30 #include "headless/public/devtools/domains/runtime.h" 31 #include "headless/public/devtools/domains/target.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/test/headless_browser_test.h" 36 #include "testing/gmock/include/gmock/gmock.h" 37 #include "testing/gtest/include/gtest/gtest.h" 38 #include "url/gurl.h" 39 40 #define EXPECT_SIZE_EQ(expected, actual) \ 41 do { \ 42 EXPECT_EQ((expected).width(), (actual).width()); \ 43 EXPECT_EQ((expected).height(), (actual).height()); \ 44 } while (false) 45 46 using testing::ElementsAre; 47 using testing::NotNull; 48 using testing::UnorderedElementsAre; 49 50 namespace headless { 51 52 class HeadlessDevToolsClientNavigationTest 53 : public HeadlessAsyncDevTooledBrowserTest, 54 page::ExperimentalObserver { 55 public: RunDevTooledTest()56 void RunDevTooledTest() override { 57 EXPECT_TRUE(embedded_test_server()->Start()); 58 std::unique_ptr<page::NavigateParams> params = 59 page::NavigateParams::Builder() 60 .SetUrl(embedded_test_server()->GetURL("/hello.html").spec()) 61 .Build(); 62 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); 63 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 64 devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); 65 run_loop.Run(); 66 devtools_client_->GetPage()->Navigate(std::move(params)); 67 } 68 OnLoadEventFired(const page::LoadEventFiredParams & params)69 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { 70 devtools_client_->GetPage()->Disable(); 71 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); 72 FinishAsynchronousTest(); 73 } 74 75 // Check that events with no parameters still get a parameters object. OnFrameResized(const page::FrameResizedParams & params)76 void OnFrameResized(const page::FrameResizedParams& params) override {} 77 }; 78 79 #if defined(OS_WIN) 80 // TODO(crbug.com/1045980): Disabled due to flakiness. 81 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientNavigationTest); 82 #else 83 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientNavigationTest); 84 #endif 85 86 class HeadlessDevToolsClientWindowManagementTest 87 : public HeadlessAsyncDevTooledBrowserTest { 88 public: SetWindowBounds(const gfx::Rect & rect,base::OnceCallback<void (std::unique_ptr<browser::SetWindowBoundsResult>)> callback)89 void SetWindowBounds( 90 const gfx::Rect& rect, 91 base::OnceCallback<void(std::unique_ptr<browser::SetWindowBoundsResult>)> 92 callback) { 93 std::unique_ptr<browser::Bounds> bounds = 94 browser::Bounds::Builder() 95 .SetLeft(rect.x()) 96 .SetTop(rect.y()) 97 .SetWidth(rect.width()) 98 .SetHeight(rect.height()) 99 .SetWindowState(browser::WindowState::NORMAL) 100 .Build(); 101 int window_id = HeadlessWebContentsImpl::From(web_contents_)->window_id(); 102 std::unique_ptr<browser::SetWindowBoundsParams> params = 103 browser::SetWindowBoundsParams::Builder() 104 .SetWindowId(window_id) 105 .SetBounds(std::move(bounds)) 106 .Build(); 107 browser_devtools_client_->GetBrowser()->GetExperimental()->SetWindowBounds( 108 std::move(params), std::move(callback)); 109 } 110 SetWindowState(const browser::WindowState state,base::OnceCallback<void (std::unique_ptr<browser::SetWindowBoundsResult>)> callback)111 void SetWindowState( 112 const browser::WindowState state, 113 base::OnceCallback<void(std::unique_ptr<browser::SetWindowBoundsResult>)> 114 callback) { 115 std::unique_ptr<browser::Bounds> bounds = 116 browser::Bounds::Builder().SetWindowState(state).Build(); 117 int window_id = HeadlessWebContentsImpl::From(web_contents_)->window_id(); 118 std::unique_ptr<browser::SetWindowBoundsParams> params = 119 browser::SetWindowBoundsParams::Builder() 120 .SetWindowId(window_id) 121 .SetBounds(std::move(bounds)) 122 .Build(); 123 browser_devtools_client_->GetBrowser()->GetExperimental()->SetWindowBounds( 124 std::move(params), std::move(callback)); 125 } 126 GetWindowBounds(base::OnceCallback<void (std::unique_ptr<browser::GetWindowBoundsResult>)> callback)127 void GetWindowBounds( 128 base::OnceCallback<void(std::unique_ptr<browser::GetWindowBoundsResult>)> 129 callback) { 130 int window_id = HeadlessWebContentsImpl::From(web_contents_)->window_id(); 131 std::unique_ptr<browser::GetWindowBoundsParams> params = 132 browser::GetWindowBoundsParams::Builder() 133 .SetWindowId(window_id) 134 .Build(); 135 136 browser_devtools_client_->GetBrowser()->GetExperimental()->GetWindowBounds( 137 std::move(params), std::move(callback)); 138 } 139 CheckWindowBounds(const gfx::Rect & bounds,const browser::WindowState state,std::unique_ptr<browser::GetWindowBoundsResult> result)140 void CheckWindowBounds( 141 const gfx::Rect& bounds, 142 const browser::WindowState state, 143 std::unique_ptr<browser::GetWindowBoundsResult> result) { 144 const browser::Bounds* actual_bounds = result->GetBounds(); 145 // Mac does not support repositioning, as we don't show any actual window. 146 #if !defined(OS_MACOSX) 147 EXPECT_EQ(bounds.x(), actual_bounds->GetLeft()); 148 EXPECT_EQ(bounds.y(), actual_bounds->GetTop()); 149 #endif // !defined(OS_MACOSX) 150 EXPECT_EQ(bounds.width(), actual_bounds->GetWidth()); 151 EXPECT_EQ(bounds.height(), actual_bounds->GetHeight()); 152 EXPECT_EQ(state, actual_bounds->GetWindowState()); 153 } 154 }; 155 156 class HeadlessDevToolsClientChangeWindowBoundsTest 157 : public HeadlessDevToolsClientWindowManagementTest { RunDevTooledTest()158 void RunDevTooledTest() override { 159 SetWindowBounds( 160 gfx::Rect(100, 200, 300, 400), 161 base::BindOnce( 162 &HeadlessDevToolsClientChangeWindowBoundsTest::OnSetWindowBounds, 163 base::Unretained(this))); 164 } 165 OnSetWindowBounds(std::unique_ptr<browser::SetWindowBoundsResult> result)166 void OnSetWindowBounds( 167 std::unique_ptr<browser::SetWindowBoundsResult> result) { 168 GetWindowBounds(base::BindOnce( 169 &HeadlessDevToolsClientChangeWindowBoundsTest::OnGetWindowBounds, 170 base::Unretained(this))); 171 } 172 OnGetWindowBounds(std::unique_ptr<browser::GetWindowBoundsResult> result)173 void OnGetWindowBounds( 174 std::unique_ptr<browser::GetWindowBoundsResult> result) { 175 CheckWindowBounds(gfx::Rect(100, 200, 300, 400), 176 browser::WindowState::NORMAL, std::move(result)); 177 FinishAsynchronousTest(); 178 } 179 }; 180 181 #if defined(OS_WIN) 182 // TODO(crbug.com/1045980): Disabled due to flakiness. 183 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F( 184 HeadlessDevToolsClientChangeWindowBoundsTest); 185 #else 186 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientChangeWindowBoundsTest); 187 #endif 188 189 class HeadlessDevToolsClientChangeWindowStateTest 190 : public HeadlessDevToolsClientWindowManagementTest { 191 public: HeadlessDevToolsClientChangeWindowStateTest(browser::WindowState state)192 explicit HeadlessDevToolsClientChangeWindowStateTest( 193 browser::WindowState state) 194 : state_(state) {} 195 RunDevTooledTest()196 void RunDevTooledTest() override { 197 SetWindowState( 198 state_, 199 base::BindOnce( 200 &HeadlessDevToolsClientChangeWindowStateTest::OnSetWindowState, 201 base::Unretained(this))); 202 } 203 OnSetWindowState(std::unique_ptr<browser::SetWindowBoundsResult> result)204 void OnSetWindowState( 205 std::unique_ptr<browser::SetWindowBoundsResult> result) { 206 GetWindowBounds(base::BindOnce( 207 &HeadlessDevToolsClientChangeWindowStateTest::OnGetWindowState, 208 base::Unretained(this))); 209 } 210 OnGetWindowState(std::unique_ptr<browser::GetWindowBoundsResult> result)211 void OnGetWindowState( 212 std::unique_ptr<browser::GetWindowBoundsResult> result) { 213 HeadlessBrowser::Options::Builder builder; 214 const HeadlessBrowser::Options kDefaultOptions = builder.Build(); 215 CheckWindowBounds(gfx::Rect(kDefaultOptions.window_size), state_, 216 std::move(result)); 217 FinishAsynchronousTest(); 218 } 219 220 protected: 221 browser::WindowState state_; 222 }; 223 224 class HeadlessDevToolsClientMinimizeWindowTest 225 : public HeadlessDevToolsClientChangeWindowStateTest { 226 public: HeadlessDevToolsClientMinimizeWindowTest()227 HeadlessDevToolsClientMinimizeWindowTest() 228 : HeadlessDevToolsClientChangeWindowStateTest( 229 browser::WindowState::MINIMIZED) {} 230 }; 231 232 #if defined(OS_WIN) 233 // TODO(crbug.com/1045980): Disabled due to flakiness. 234 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F( 235 HeadlessDevToolsClientMinimizeWindowTest); 236 #else 237 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientMinimizeWindowTest); 238 #endif 239 240 class HeadlessDevToolsClientMaximizeWindowTest 241 : public HeadlessDevToolsClientChangeWindowStateTest { 242 public: HeadlessDevToolsClientMaximizeWindowTest()243 HeadlessDevToolsClientMaximizeWindowTest() 244 : HeadlessDevToolsClientChangeWindowStateTest( 245 browser::WindowState::MAXIMIZED) {} 246 }; 247 248 #if defined(OS_WIN) 249 // TODO(crbug.com/1045980): Disabled due to flakiness. 250 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F( 251 HeadlessDevToolsClientMaximizeWindowTest); 252 #else 253 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientMaximizeWindowTest); 254 #endif 255 256 class HeadlessDevToolsClientFullscreenWindowTest 257 : public HeadlessDevToolsClientChangeWindowStateTest { 258 public: HeadlessDevToolsClientFullscreenWindowTest()259 HeadlessDevToolsClientFullscreenWindowTest() 260 : HeadlessDevToolsClientChangeWindowStateTest( 261 browser::WindowState::FULLSCREEN) {} 262 }; 263 264 #if defined(OS_WIN) 265 // TODO(crbug.com/1045980): Disabled due to flakiness. 266 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F( 267 HeadlessDevToolsClientFullscreenWindowTest); 268 #else 269 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientFullscreenWindowTest); 270 #endif 271 272 class HeadlessDevToolsClientEvalTest 273 : public HeadlessAsyncDevTooledBrowserTest { 274 public: RunDevTooledTest()275 void RunDevTooledTest() override { 276 std::unique_ptr<runtime::EvaluateParams> params = 277 runtime::EvaluateParams::Builder().SetExpression("1 + 2").Build(); 278 devtools_client_->GetRuntime()->Evaluate( 279 std::move(params), 280 base::BindOnce(&HeadlessDevToolsClientEvalTest::OnFirstResult, 281 base::Unretained(this))); 282 // Test the convenience overload which only takes the required command 283 // parameters. 284 devtools_client_->GetRuntime()->Evaluate( 285 "24 * 7", 286 base::BindOnce(&HeadlessDevToolsClientEvalTest::OnSecondResult, 287 base::Unretained(this))); 288 } 289 OnFirstResult(std::unique_ptr<runtime::EvaluateResult> result)290 void OnFirstResult(std::unique_ptr<runtime::EvaluateResult> result) { 291 EXPECT_TRUE(result->GetResult()->HasValue()); 292 EXPECT_EQ(3, result->GetResult()->GetValue()->GetInt()); 293 } 294 OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result)295 void OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result) { 296 EXPECT_TRUE(result->GetResult()->HasValue()); 297 EXPECT_EQ(168, result->GetResult()->GetValue()->GetInt()); 298 FinishAsynchronousTest(); 299 } 300 }; 301 302 #if defined(OS_WIN) 303 // TODO(crbug.com/1045980): Disabled due to flakiness. 304 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientEvalTest); 305 #else 306 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientEvalTest); 307 #endif 308 309 class HeadlessDevToolsClientCallbackTest 310 : public HeadlessAsyncDevTooledBrowserTest { 311 public: HeadlessDevToolsClientCallbackTest()312 HeadlessDevToolsClientCallbackTest() : first_result_received_(false) {} 313 RunDevTooledTest()314 void RunDevTooledTest() override { 315 // Null callback without parameters. 316 devtools_client_->GetPage()->Enable(); 317 // Null callback with parameters. 318 devtools_client_->GetRuntime()->Evaluate("true"); 319 // Non-null callback without parameters. 320 devtools_client_->GetPage()->Disable( 321 base::BindOnce(&HeadlessDevToolsClientCallbackTest::OnFirstResult, 322 base::Unretained(this))); 323 // Non-null callback with parameters. 324 devtools_client_->GetRuntime()->Evaluate( 325 "true", 326 base::BindOnce(&HeadlessDevToolsClientCallbackTest::OnSecondResult, 327 base::Unretained(this))); 328 } 329 OnFirstResult()330 void OnFirstResult() { 331 EXPECT_FALSE(first_result_received_); 332 first_result_received_ = true; 333 } 334 OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result)335 void OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result) { 336 EXPECT_TRUE(first_result_received_); 337 FinishAsynchronousTest(); 338 } 339 340 private: 341 bool first_result_received_; 342 }; 343 344 #if defined(OS_WIN) 345 // TODO(crbug.com/1045980): Disabled due to flakiness. 346 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientCallbackTest); 347 #else 348 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientCallbackTest); 349 #endif 350 351 class HeadlessDevToolsClientObserverTest 352 : public HeadlessAsyncDevTooledBrowserTest, 353 network::Observer { 354 public: RunDevTooledTest()355 void RunDevTooledTest() override { 356 EXPECT_TRUE(embedded_test_server()->Start()); 357 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 358 devtools_client_->GetNetwork()->AddObserver(this); 359 devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); 360 run_loop.Run(); 361 362 devtools_client_->GetPage()->Navigate( 363 embedded_test_server()->GetURL("/hello.html").spec()); 364 } 365 OnRequestWillBeSent(const network::RequestWillBeSentParams & params)366 void OnRequestWillBeSent( 367 const network::RequestWillBeSentParams& params) override { 368 EXPECT_EQ("GET", params.GetRequest()->GetMethod()); 369 EXPECT_EQ(embedded_test_server()->GetURL("/hello.html").spec(), 370 params.GetRequest()->GetUrl()); 371 } 372 OnResponseReceived(const network::ResponseReceivedParams & params)373 void OnResponseReceived( 374 const network::ResponseReceivedParams& params) override { 375 EXPECT_EQ(200, params.GetResponse()->GetStatus()); 376 EXPECT_EQ("OK", params.GetResponse()->GetStatusText()); 377 const base::Value* content_type_value = 378 params.GetResponse()->GetHeaders()->FindKey("Content-Type"); 379 ASSERT_THAT(content_type_value, NotNull()); 380 EXPECT_EQ("text/html", content_type_value->GetString()); 381 382 devtools_client_->GetNetwork()->Disable(); 383 devtools_client_->GetNetwork()->RemoveObserver(this); 384 FinishAsynchronousTest(); 385 } 386 }; 387 388 #if defined(OS_WIN) 389 // TODO(crbug.com/1045980): Disabled due to flakiness. 390 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientObserverTest); 391 #else 392 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientObserverTest); 393 #endif 394 395 class HeadlessDevToolsClientExperimentalTest 396 : public HeadlessAsyncDevTooledBrowserTest, 397 page::ExperimentalObserver { 398 public: RunDevTooledTest()399 void RunDevTooledTest() override { 400 EXPECT_TRUE(embedded_test_server()->Start()); 401 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 402 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); 403 devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); 404 run_loop.Run(); 405 // Check that experimental commands require parameter objects. 406 devtools_client_->GetRuntime() 407 ->GetExperimental() 408 ->SetCustomObjectFormatterEnabled( 409 runtime::SetCustomObjectFormatterEnabledParams::Builder() 410 .SetEnabled(false) 411 .Build()); 412 413 // Check that a previously experimental command which takes no parameters 414 // still works by giving it a parameter object. 415 devtools_client_->GetRuntime()->GetExperimental()->RunIfWaitingForDebugger( 416 runtime::RunIfWaitingForDebuggerParams::Builder().Build()); 417 418 devtools_client_->GetPage()->Navigate( 419 embedded_test_server()->GetURL("/hello.html").spec()); 420 } 421 OnFrameStoppedLoading(const page::FrameStoppedLoadingParams & params)422 void OnFrameStoppedLoading( 423 const page::FrameStoppedLoadingParams& params) override { 424 devtools_client_->GetPage()->Disable(); 425 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); 426 427 // Check that a non-experimental command which has no return value can be 428 // called with a void() callback. 429 devtools_client_->GetPage()->Reload( 430 page::ReloadParams::Builder().Build(), 431 base::BindOnce(&HeadlessDevToolsClientExperimentalTest::OnReloadStarted, 432 base::Unretained(this))); 433 } 434 OnReloadStarted()435 void OnReloadStarted() { FinishAsynchronousTest(); } 436 }; 437 438 #if defined(OS_WIN) 439 // TODO(crbug.com/1045980): Disabled due to flakiness. 440 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F( 441 HeadlessDevToolsClientExperimentalTest); 442 #else 443 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientExperimentalTest); 444 #endif 445 446 class HeadlessDevToolsNavigationControlTest 447 : public HeadlessAsyncDevTooledBrowserTest, 448 network::ExperimentalObserver, 449 page::ExperimentalObserver { 450 public: RunDevTooledTest()451 void RunDevTooledTest() override { 452 EXPECT_TRUE(embedded_test_server()->Start()); 453 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 454 devtools_client_->GetPage()->GetExperimental()->AddObserver(this); 455 devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this); 456 devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); 457 run_loop.Run(); 458 devtools_client_->GetNetwork()->Enable(); 459 460 std::unique_ptr<headless::network::RequestPattern> match_all = 461 headless::network::RequestPattern::Builder().SetUrlPattern("*").Build(); 462 std::vector<std::unique_ptr<headless::network::RequestPattern>> patterns; 463 patterns.push_back(std::move(match_all)); 464 devtools_client_->GetNetwork()->GetExperimental()->SetRequestInterception( 465 network::SetRequestInterceptionParams::Builder() 466 .SetPatterns(std::move(patterns)) 467 .Build()); 468 devtools_client_->GetPage()->Navigate( 469 embedded_test_server()->GetURL("/hello.html").spec()); 470 } 471 OnRequestIntercepted(const network::RequestInterceptedParams & params)472 void OnRequestIntercepted( 473 const network::RequestInterceptedParams& params) override { 474 if (params.GetIsNavigationRequest()) 475 navigation_requested_ = true; 476 // Allow the navigation to proceed. 477 devtools_client_->GetNetwork() 478 ->GetExperimental() 479 ->ContinueInterceptedRequest( 480 network::ContinueInterceptedRequestParams::Builder() 481 .SetInterceptionId(params.GetInterceptionId()) 482 .Build()); 483 } 484 OnFrameStoppedLoading(const page::FrameStoppedLoadingParams & params)485 void OnFrameStoppedLoading( 486 const page::FrameStoppedLoadingParams& params) override { 487 EXPECT_TRUE(navigation_requested_); 488 FinishAsynchronousTest(); 489 } 490 491 private: 492 bool navigation_requested_ = false; 493 }; 494 495 #if defined(OS_WIN) 496 // TODO(crbug.com/1045980): Disabled due to flakiness. 497 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsNavigationControlTest); 498 #else 499 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsNavigationControlTest); 500 #endif 501 502 class HeadlessCrashObserverTest : public HeadlessAsyncDevTooledBrowserTest, 503 inspector::ExperimentalObserver { 504 public: RunDevTooledTest()505 void RunDevTooledTest() override { 506 devtools_client_->GetInspector()->GetExperimental()->AddObserver(this); 507 devtools_client_->GetInspector()->GetExperimental()->Enable( 508 inspector::EnableParams::Builder().Build()); 509 devtools_client_->GetPage()->Enable(); 510 devtools_client_->GetPage()->Navigate(content::kChromeUICrashURL); 511 } 512 OnTargetCrashed(const inspector::TargetCrashedParams & params)513 void OnTargetCrashed(const inspector::TargetCrashedParams& params) override { 514 FinishAsynchronousTest(); 515 render_process_exited_ = true; 516 } 517 518 // Make sure we don't fail because the renderer crashed! RenderProcessExited(base::TerminationStatus status,int exit_code)519 void RenderProcessExited(base::TerminationStatus status, 520 int exit_code) override { 521 #if defined(OS_WIN) && defined(ADDRESS_SANITIZER) 522 // TODO(crbug.com/845011): Make ASan not interfere and expect a crash. 523 // ASan's normal error exit code is 1, which base categorizes as the process 524 // being killed. 525 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); 526 #elif defined(OS_WIN) || defined(OS_MACOSX) 527 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); 528 #else 529 EXPECT_EQ(base::TERMINATION_STATUS_ABNORMAL_TERMINATION, status); 530 #endif 531 } 532 533 private: 534 content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_; 535 }; 536 537 #if defined(OS_WIN) 538 // TODO(crbug.com/1045980): Disabled due to flakiness. 539 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessCrashObserverTest); 540 #else 541 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessCrashObserverTest); 542 #endif 543 544 class HeadlessDevToolsClientAttachTest 545 : public HeadlessAsyncDevTooledBrowserTest { 546 public: RunDevTooledTest()547 void RunDevTooledTest() override { 548 other_devtools_client_ = HeadlessDevToolsClient::Create(); 549 HeadlessDevToolsTarget* devtools_target = 550 web_contents_->GetDevToolsTarget(); 551 552 EXPECT_TRUE(devtools_target->IsAttached()); 553 // Detach the existing client, attach the other client. 554 devtools_target->DetachClient(devtools_client_.get()); 555 EXPECT_FALSE(devtools_target->IsAttached()); 556 devtools_target->AttachClient(other_devtools_client_.get()); 557 EXPECT_TRUE(devtools_target->IsAttached()); 558 559 // Now, let's make sure this devtools client works. 560 other_devtools_client_->GetRuntime()->Evaluate( 561 "24 * 7", 562 base::BindOnce(&HeadlessDevToolsClientAttachTest::OnFirstResult, 563 base::Unretained(this))); 564 } 565 OnFirstResult(std::unique_ptr<runtime::EvaluateResult> result)566 void OnFirstResult(std::unique_ptr<runtime::EvaluateResult> result) { 567 EXPECT_TRUE(result->GetResult()->HasValue()); 568 EXPECT_EQ(24 * 7, result->GetResult()->GetValue()->GetInt()); 569 570 HeadlessDevToolsTarget* devtools_target = 571 web_contents_->GetDevToolsTarget(); 572 573 EXPECT_TRUE(devtools_target->IsAttached()); 574 devtools_target->DetachClient(other_devtools_client_.get()); 575 EXPECT_FALSE(devtools_target->IsAttached()); 576 devtools_target->AttachClient(devtools_client_.get()); 577 EXPECT_TRUE(devtools_target->IsAttached()); 578 579 devtools_client_->GetRuntime()->Evaluate( 580 "27 * 4", 581 base::BindOnce(&HeadlessDevToolsClientAttachTest::OnSecondResult, 582 base::Unretained(this))); 583 } 584 OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result)585 void OnSecondResult(std::unique_ptr<runtime::EvaluateResult> result) { 586 EXPECT_TRUE(result->GetResult()->HasValue()); 587 EXPECT_EQ(27 * 4, result->GetResult()->GetValue()->GetInt()); 588 589 // If everything worked, this call will not crash, since it 590 // detaches devtools_client_. 591 FinishAsynchronousTest(); 592 } 593 594 protected: 595 std::unique_ptr<HeadlessDevToolsClient> other_devtools_client_; 596 }; 597 598 #if defined(OS_WIN) 599 // TODO(crbug.com/1045980): Disabled due to flakiness. 600 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientAttachTest); 601 #else 602 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientAttachTest); 603 #endif 604 605 class HeadlessDevToolsMethodCallErrorTest 606 : public HeadlessAsyncDevTooledBrowserTest, 607 public page::Observer { 608 public: RunDevTooledTest()609 void RunDevTooledTest() override { 610 EXPECT_TRUE(embedded_test_server()->Start()); 611 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 612 devtools_client_->GetPage()->AddObserver(this); 613 devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); 614 run_loop.Run(); 615 devtools_client_->GetPage()->Navigate( 616 embedded_test_server()->GetURL("/hello.html").spec()); 617 } 618 OnLoadEventFired(const page::LoadEventFiredParams & params)619 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { 620 devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this); 621 devtools_client_->GetDOM()->GetDocument( 622 base::BindOnce(&HeadlessDevToolsMethodCallErrorTest::OnGetDocument, 623 base::Unretained(this))); 624 } 625 OnGetDocument(std::unique_ptr<dom::GetDocumentResult> result)626 void OnGetDocument(std::unique_ptr<dom::GetDocumentResult> result) { 627 devtools_client_->GetDOM()->QuerySelector( 628 dom::QuerySelectorParams::Builder() 629 .SetNodeId(result->GetRoot()->GetNodeId()) 630 .SetSelector("<o_O>") 631 .Build(), 632 base::BindOnce(&HeadlessDevToolsMethodCallErrorTest::OnQuerySelector, 633 base::Unretained(this))); 634 } 635 OnQuerySelector(std::unique_ptr<dom::QuerySelectorResult> result)636 void OnQuerySelector(std::unique_ptr<dom::QuerySelectorResult> result) { 637 EXPECT_EQ(nullptr, result); 638 FinishAsynchronousTest(); 639 } 640 }; 641 642 #if defined(OS_WIN) 643 // TODO(crbug.com/1045980): Disabled due to flakiness. 644 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsMethodCallErrorTest); 645 #else 646 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsMethodCallErrorTest); 647 #endif 648 649 class HeadlessDevToolsNetworkBlockedUrlTest 650 : public HeadlessAsyncDevTooledBrowserTest, 651 public page::Observer, 652 public network::Observer { 653 public: RunDevTooledTest()654 void RunDevTooledTest() override { 655 EXPECT_TRUE(embedded_test_server()->Start()); 656 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 657 devtools_client_->GetPage()->AddObserver(this); 658 devtools_client_->GetPage()->Enable(); 659 devtools_client_->GetNetwork()->AddObserver(this); 660 devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); 661 run_loop.Run(); 662 std::vector<std::string> blockedUrls; 663 blockedUrls.push_back("dom_tree_test.css"); 664 devtools_client_->GetNetwork()->GetExperimental()->SetBlockedURLs( 665 network::SetBlockedURLsParams::Builder().SetUrls(blockedUrls).Build()); 666 devtools_client_->GetPage()->Navigate( 667 embedded_test_server()->GetURL("/dom_tree_test.html").spec()); 668 } 669 GetUrlPath(const std::string & url) const670 std::string GetUrlPath(const std::string& url) const { 671 GURL gurl(url); 672 return gurl.path(); 673 } 674 OnRequestWillBeSent(const network::RequestWillBeSentParams & params)675 void OnRequestWillBeSent( 676 const network::RequestWillBeSentParams& params) override { 677 std::string path = GetUrlPath(params.GetRequest()->GetUrl()); 678 requests_to_be_sent_.push_back(path); 679 request_id_to_path_[params.GetRequestId()] = path; 680 } 681 OnResponseReceived(const network::ResponseReceivedParams & params)682 void OnResponseReceived( 683 const network::ResponseReceivedParams& params) override { 684 responses_received_.push_back(GetUrlPath(params.GetResponse()->GetUrl())); 685 } 686 OnLoadingFailed(const network::LoadingFailedParams & failed)687 void OnLoadingFailed(const network::LoadingFailedParams& failed) override { 688 failures_.push_back(request_id_to_path_[failed.GetRequestId()]); 689 EXPECT_EQ(network::BlockedReason::INSPECTOR, failed.GetBlockedReason()); 690 } 691 OnLoadEventFired(const page::LoadEventFiredParams &)692 void OnLoadEventFired(const page::LoadEventFiredParams&) override { 693 EXPECT_THAT( 694 requests_to_be_sent_, 695 testing::UnorderedElementsAre("/dom_tree_test.html", 696 "/dom_tree_test.css", "/iframe.html")); 697 EXPECT_THAT(responses_received_, 698 ElementsAre("/dom_tree_test.html", "/iframe.html")); 699 EXPECT_THAT(failures_, ElementsAre("/dom_tree_test.css")); 700 FinishAsynchronousTest(); 701 } 702 703 std::map<std::string, std::string> request_id_to_path_; 704 std::vector<std::string> requests_to_be_sent_; 705 std::vector<std::string> responses_received_; 706 std::vector<std::string> failures_; 707 }; 708 709 #if defined(OS_WIN) 710 // TODO(crbug.com/1045980): Disabled due to flakiness. 711 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsNetworkBlockedUrlTest); 712 #else 713 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsNetworkBlockedUrlTest); 714 #endif 715 716 class DevToolsNetworkOfflineEmulationTest 717 : public HeadlessAsyncDevTooledBrowserTest, 718 public page::Observer, 719 public network::Observer { RunDevTooledTest()720 void RunDevTooledTest() override { 721 EXPECT_TRUE(embedded_test_server()->Start()); 722 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 723 devtools_client_->GetPage()->AddObserver(this); 724 devtools_client_->GetPage()->Enable(); 725 devtools_client_->GetNetwork()->AddObserver(this); 726 devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); 727 run_loop.Run(); 728 std::unique_ptr<network::EmulateNetworkConditionsParams> params = 729 network::EmulateNetworkConditionsParams::Builder() 730 .SetOffline(true) 731 .SetLatency(0) 732 .SetDownloadThroughput(0) 733 .SetUploadThroughput(0) 734 .Build(); 735 devtools_client_->GetNetwork()->EmulateNetworkConditions(std::move(params)); 736 devtools_client_->GetPage()->Navigate( 737 embedded_test_server()->GetURL("/hello.html").spec()); 738 } 739 OnLoadingFailed(const network::LoadingFailedParams & failed)740 void OnLoadingFailed(const network::LoadingFailedParams& failed) override { 741 EXPECT_EQ("net::ERR_INTERNET_DISCONNECTED", failed.GetErrorText()); 742 FinishAsynchronousTest(); 743 } 744 }; 745 746 #if defined(OS_WIN) 747 // TODO(crbug.com/1045980): Disabled due to flakiness. 748 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsNetworkOfflineEmulationTest); 749 #else 750 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsNetworkOfflineEmulationTest); 751 #endif 752 753 class RawDevtoolsProtocolTest 754 : public HeadlessAsyncDevTooledBrowserTest, 755 public HeadlessDevToolsClient::RawProtocolListener { 756 public: RunDevTooledTest()757 void RunDevTooledTest() override { 758 devtools_client_->SetRawProtocolListener(this); 759 760 base::DictionaryValue message; 761 message.SetInteger("id", devtools_client_->GetNextRawDevToolsMessageId()); 762 message.SetString("method", "Runtime.evaluate"); 763 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); 764 params->SetString("expression", "1+1"); 765 message.Set("params", std::move(params)); 766 std::string json_message; 767 base::JSONWriter::Write(message, &json_message); 768 devtools_client_->SendRawDevToolsMessage(json_message); 769 } 770 OnProtocolMessage(base::span<const uint8_t> json_message,const base::DictionaryValue & parsed_message)771 bool OnProtocolMessage(base::span<const uint8_t> json_message, 772 const base::DictionaryValue& parsed_message) override { 773 EXPECT_EQ( 774 "{\"id\":1,\"result\":{\"result\":{\"type\":\"number\"," 775 "\"value\":2,\"description\":\"2\"}}}", 776 std::string(json_message.begin(), json_message.end())); 777 778 FinishAsynchronousTest(); 779 return true; 780 } 781 }; 782 783 #if defined(OS_WIN) 784 // TODO(crbug.com/1045980): Disabled due to flakiness. 785 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(RawDevtoolsProtocolTest); 786 #else 787 HEADLESS_ASYNC_DEVTOOLED_TEST_F(RawDevtoolsProtocolTest); 788 #endif 789 790 class DevToolsAttachAndDetachNotifications 791 : public HeadlessAsyncDevTooledBrowserTest { 792 public: DevToolsClientAttached()793 void DevToolsClientAttached() override { dev_tools_client_attached_ = true; } 794 RunDevTooledTest()795 void RunDevTooledTest() override { 796 EXPECT_TRUE(dev_tools_client_attached_); 797 FinishAsynchronousTest(); 798 } 799 DevToolsClientDetached()800 void DevToolsClientDetached() override { dev_tools_client_detached_ = true; } 801 TearDownOnMainThread()802 void TearDownOnMainThread() override { 803 EXPECT_TRUE(dev_tools_client_detached_); 804 } 805 806 private: 807 bool dev_tools_client_attached_ = false; 808 bool dev_tools_client_detached_ = false; 809 }; 810 811 #if defined(OS_WIN) 812 // TODO(crbug.com/1045980): Disabled due to flakiness. 813 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsAttachAndDetachNotifications); 814 #else 815 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsAttachAndDetachNotifications); 816 #endif 817 818 class DomTreeExtractionBrowserTest : public HeadlessAsyncDevTooledBrowserTest, 819 public page::Observer { 820 public: RunDevTooledTest()821 void RunDevTooledTest() override { 822 EXPECT_TRUE(embedded_test_server()->Start()); 823 devtools_client_->GetPage()->AddObserver(this); 824 devtools_client_->GetPage()->Enable(); 825 devtools_client_->GetPage()->Navigate( 826 embedded_test_server()->GetURL("/dom_tree_test.html").spec()); 827 } 828 OnLoadEventFired(const page::LoadEventFiredParams & params)829 void OnLoadEventFired(const page::LoadEventFiredParams& params) override { 830 devtools_client_->GetPage()->Disable(); 831 devtools_client_->GetPage()->RemoveObserver(this); 832 833 std::vector<std::string> css_whitelist = { 834 "color", "display", "font-style", "font-family", 835 "margin-left", "margin-right", "margin-top", "margin-bottom"}; 836 devtools_client_->GetDOMSnapshot()->GetExperimental()->GetSnapshot( 837 dom_snapshot::GetSnapshotParams::Builder() 838 .SetComputedStyleWhitelist(std::move(css_whitelist)) 839 .Build(), 840 base::BindOnce(&DomTreeExtractionBrowserTest::OnGetSnapshotResult, 841 base::Unretained(this))); 842 } 843 OnGetSnapshotResult(std::unique_ptr<dom_snapshot::GetSnapshotResult> result)844 void OnGetSnapshotResult( 845 std::unique_ptr<dom_snapshot::GetSnapshotResult> result) { 846 GURL::Replacements replace_port; 847 replace_port.SetPortStr(""); 848 849 std::vector<std::unique_ptr<base::DictionaryValue>> dom_nodes( 850 result->GetDomNodes()->size()); 851 852 // For convenience, flatten the dom tree into an array of dicts. 853 for (size_t i = 0; i < result->GetDomNodes()->size(); i++) { 854 dom_snapshot::DOMNode* node = (*result->GetDomNodes())[i].get(); 855 856 dom_nodes[i].reset( 857 static_cast<base::DictionaryValue*>(node->Serialize().release())); 858 base::DictionaryValue* node_dict = dom_nodes[i].get(); 859 860 // Node IDs are assigned in a non deterministic way. 861 if (node_dict->FindKey("backendNodeId")) 862 node_dict->SetString("backendNodeId", "?"); 863 864 // Frame IDs are random. 865 if (node_dict->FindKey("frameId")) 866 node_dict->SetString("frameId", "?"); 867 868 // Ports are random. 869 if (base::Value* base_url_value = node_dict->FindKey("baseURL")) { 870 node_dict->SetString("baseURL", GURL(base_url_value->GetString()) 871 .ReplaceComponents(replace_port) 872 .spec()); 873 } 874 875 if (base::Value* document_url_value = node_dict->FindKey("documentURL")) { 876 node_dict->SetString("documentURL", 877 GURL(document_url_value->GetString()) 878 .ReplaceComponents(replace_port) 879 .spec()); 880 } 881 882 // Merge LayoutTreeNode data into the dictionary. 883 if (base::Value* layout_node_index_value = 884 node_dict->FindKey("layoutNodeIndex")) { 885 int layout_node_index = layout_node_index_value->GetInt(); 886 ASSERT_LE(0, layout_node_index); 887 ASSERT_GT(result->GetLayoutTreeNodes()->size(), 888 static_cast<size_t>(layout_node_index)); 889 const std::unique_ptr<dom_snapshot::LayoutTreeNode>& layout_node = 890 (*result->GetLayoutTreeNodes())[layout_node_index]; 891 892 node_dict->Set("boundingBox", 893 layout_node->GetBoundingBox()->Serialize()); 894 895 if (layout_node->HasLayoutText()) 896 node_dict->SetString("layoutText", layout_node->GetLayoutText()); 897 898 if (layout_node->HasStyleIndex()) 899 node_dict->SetInteger("styleIndex", layout_node->GetStyleIndex()); 900 901 if (layout_node->HasInlineTextNodes()) { 902 std::unique_ptr<base::ListValue> inline_text_nodes( 903 new base::ListValue()); 904 for (const std::unique_ptr<dom_snapshot::InlineTextBox>& 905 inline_text_box : *layout_node->GetInlineTextNodes()) { 906 size_t index = inline_text_nodes->GetSize(); 907 inline_text_nodes->Set(index, inline_text_box->Serialize()); 908 } 909 node_dict->Set("inlineTextNodes", std::move(inline_text_nodes)); 910 } 911 } 912 } 913 914 std::vector<std::unique_ptr<base::DictionaryValue>> computed_styles( 915 result->GetComputedStyles()->size()); 916 917 for (size_t i = 0; i < result->GetComputedStyles()->size(); i++) { 918 std::unique_ptr<base::DictionaryValue> style(new base::DictionaryValue()); 919 for (const auto& style_property : 920 *(*result->GetComputedStyles())[i]->GetProperties()) { 921 style->SetString(style_property->GetName(), style_property->GetValue()); 922 } 923 computed_styles[i] = std::move(style); 924 } 925 926 base::ThreadRestrictions::SetIOAllowed(true); 927 base::FilePath source_root_dir; 928 base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir); 929 base::FilePath expected_dom_nodes_path = 930 source_root_dir.Append(FILE_PATH_LITERAL( 931 "headless/lib/dom_tree_extraction_expected_nodes.txt")); 932 std::string expected_dom_nodes; 933 ASSERT_TRUE( 934 base::ReadFileToString(expected_dom_nodes_path, &expected_dom_nodes)); 935 936 std::string dom_nodes_result; 937 for (size_t i = 0; i < dom_nodes.size(); i++) { 938 std::string result_json; 939 base::JSONWriter::WriteWithOptions( 940 *dom_nodes[i], base::JSONWriter::OPTIONS_PRETTY_PRINT, &result_json); 941 942 dom_nodes_result += result_json; 943 } 944 945 #if defined(OS_WIN) 946 ASSERT_TRUE(base::RemoveChars(dom_nodes_result, "\r", &dom_nodes_result)); 947 #endif 948 949 EXPECT_EQ(expected_dom_nodes, dom_nodes_result); 950 951 base::FilePath expected_styles_path = 952 source_root_dir.Append(FILE_PATH_LITERAL( 953 "headless/lib/dom_tree_extraction_expected_styles.txt")); 954 std::string expected_computed_styles; 955 ASSERT_TRUE(base::ReadFileToString(expected_styles_path, 956 &expected_computed_styles)); 957 958 std::string computed_styles_result; 959 for (size_t i = 0; i < computed_styles.size(); i++) { 960 std::string result_json; 961 base::JSONWriter::WriteWithOptions(*computed_styles[i], 962 base::JSONWriter::OPTIONS_PRETTY_PRINT, 963 &result_json); 964 965 computed_styles_result += result_json; 966 } 967 968 #if defined(OS_WIN) 969 ASSERT_TRUE(base::RemoveChars(computed_styles_result, "\r", 970 &computed_styles_result)); 971 #endif 972 973 EXPECT_EQ(expected_computed_styles, computed_styles_result); 974 FinishAsynchronousTest(); 975 } 976 }; 977 978 #if defined(OS_WIN) 979 // TODO(crbug.com/1045980): Disabled due to flakiness. 980 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(DomTreeExtractionBrowserTest); 981 #else 982 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DomTreeExtractionBrowserTest); 983 #endif 984 985 // This feature uses network observation and works exactly and only for 986 // network::ErrorReason::BLOCKED_BY_CLIENT modifications that are initiated 987 // via network::ExperimentalObserver. 988 class BlockedByClient_NetworkObserver_Test 989 : public HeadlessAsyncDevTooledBrowserTest, 990 public network::ExperimentalObserver, 991 public page::Observer { 992 public: RunDevTooledTest()993 void RunDevTooledTest() override { 994 ASSERT_TRUE(embedded_test_server()->Start()); 995 996 // Intercept all network requests. 997 devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this); 998 devtools_client_->GetNetwork()->Enable(); 999 std::vector<std::unique_ptr<network::RequestPattern>> patterns; 1000 patterns.emplace_back( 1001 network::RequestPattern::Builder().SetUrlPattern("*").Build()); 1002 devtools_client_->GetNetwork()->GetExperimental()->SetRequestInterception( 1003 network::SetRequestInterceptionParams::Builder() 1004 .SetPatterns(std::move(patterns)) 1005 .Build()); 1006 1007 // For observing OnLoadEventFired. 1008 devtools_client_->GetPage()->AddObserver(this); 1009 devtools_client_->GetPage()->Enable(); 1010 1011 devtools_client_->GetPage()->Navigate( 1012 embedded_test_server()->GetURL("/resource_cancel_test.html").spec()); 1013 } 1014 1015 // Overrides network::ExperimentalObserver. OnRequestIntercepted(const network::RequestInterceptedParams & params)1016 void OnRequestIntercepted( 1017 const network::RequestInterceptedParams& params) override { 1018 urls_seen_.push_back(GURL(params.GetRequest()->GetUrl()).ExtractFileName()); 1019 1020 auto continue_intercept_params = 1021 network::ContinueInterceptedRequestParams::Builder() 1022 .SetInterceptionId(params.GetInterceptionId()) 1023 .Build(); 1024 1025 // We *abort* fetching Ahem.ttf, and *fail* for test.jpg 1026 // to verify that both ways result in a failed loading event, 1027 // which we'll observe in OnLoadingFailed below. 1028 // Also, we abort iframe2.html because it turns out frame interception 1029 // uses a very different codepath than other resources. 1030 if (EndsWith(params.GetRequest()->GetUrl(), "/test.jpg", 1031 base::CompareCase::SENSITIVE)) { 1032 continue_intercept_params->SetErrorReason( 1033 network::ErrorReason::BLOCKED_BY_CLIENT); 1034 } else if (EndsWith(params.GetRequest()->GetUrl(), "/Ahem.ttf", 1035 base::CompareCase::SENSITIVE)) { 1036 continue_intercept_params->SetErrorReason( 1037 network::ErrorReason::BLOCKED_BY_CLIENT); 1038 } else if (EndsWith(params.GetRequest()->GetUrl(), "/iframe2.html", 1039 base::CompareCase::SENSITIVE)) { 1040 continue_intercept_params->SetErrorReason( 1041 network::ErrorReason::BLOCKED_BY_CLIENT); 1042 } 1043 1044 devtools_client_->GetNetwork() 1045 ->GetExperimental() 1046 ->ContinueInterceptedRequest(std::move(continue_intercept_params)); 1047 } 1048 1049 // Overrides network::ExperimentalObserver. OnRequestWillBeSent(const network::RequestWillBeSentParams & params)1050 void OnRequestWillBeSent( 1051 const network::RequestWillBeSentParams& params) override { 1052 // Here, we just record the URLs (filenames) for each request ID, since 1053 // we won't have access to them in ::OnLoadingFailed below. 1054 urls_by_id_[params.GetRequestId()] = 1055 GURL(params.GetRequest()->GetUrl()).ExtractFileName(); 1056 } 1057 1058 // Overrides network::ExperimentalObserver. OnLoadingFailed(const network::LoadingFailedParams & params)1059 void OnLoadingFailed(const network::LoadingFailedParams& params) override { 1060 // Record the failed loading events so we can verify below that we 1061 // received the events. 1062 urls_that_failed_to_load_.push_back(urls_by_id_[params.GetRequestId()]); 1063 EXPECT_EQ(network::BlockedReason::INSPECTOR, params.GetBlockedReason()); 1064 } 1065 1066 // Overrides page::ExperimentalObserver. OnLoadEventFired(const page::LoadEventFiredParams &)1067 void OnLoadEventFired(const page::LoadEventFiredParams&) override { 1068 EXPECT_THAT(urls_that_failed_to_load_, 1069 UnorderedElementsAre("test.jpg", "Ahem.ttf", "iframe2.html")); 1070 EXPECT_THAT(urls_seen_, UnorderedElementsAre("resource_cancel_test.html", 1071 "dom_tree_test.css", 1072 "test.jpg", "iframe.html", 1073 "iframe2.html", "Ahem.ttf")); 1074 FinishAsynchronousTest(); 1075 } 1076 1077 private: 1078 std::vector<std::string> urls_seen_; 1079 std::vector<std::string> urls_that_failed_to_load_; 1080 std::map<std::string, std::string> urls_by_id_; 1081 }; 1082 1083 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(BlockedByClient_NetworkObserver_Test); 1084 1085 class DevToolsSetCookieTest : public HeadlessAsyncDevTooledBrowserTest, 1086 public network::Observer { 1087 public: RunDevTooledTest()1088 void RunDevTooledTest() override { 1089 EXPECT_TRUE(embedded_test_server()->Start()); 1090 devtools_client_->GetNetwork()->AddObserver(this); 1091 1092 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 1093 devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); 1094 run_loop.Run(); 1095 1096 devtools_client_->GetPage()->Navigate( 1097 embedded_test_server()->GetURL("/set-cookie?cookie1").spec()); 1098 } 1099 OnResponseReceived(const network::ResponseReceivedParams & params)1100 void OnResponseReceived( 1101 const network::ResponseReceivedParams& params) override { 1102 EXPECT_NE(std::string::npos, params.GetResponse()->GetHeadersText().find( 1103 "Set-Cookie: cookie1")); 1104 FinishAsynchronousTest(); 1105 } 1106 }; 1107 1108 #if defined(OS_WIN) 1109 // TODO(crbug.com/1045980): Disabled due to flakiness. 1110 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsSetCookieTest); 1111 #else 1112 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsSetCookieTest); 1113 #endif 1114 1115 class DevtoolsInterceptionWithAuthProxyTest 1116 : public HeadlessAsyncDevTooledBrowserTest, 1117 public network::ExperimentalObserver, 1118 public page::Observer { 1119 public: DevtoolsInterceptionWithAuthProxyTest()1120 DevtoolsInterceptionWithAuthProxyTest() 1121 : proxy_server_(net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, 1122 base::FilePath(FILE_PATH_LITERAL("headless/test/data"))) { 1123 } 1124 SetUp()1125 void SetUp() override { 1126 ASSERT_TRUE(proxy_server_.Start()); 1127 HeadlessAsyncDevTooledBrowserTest::SetUp(); 1128 } 1129 RunDevTooledTest()1130 void RunDevTooledTest() override { 1131 EXPECT_TRUE(embedded_test_server()->Start()); 1132 devtools_client_->GetNetwork()->GetExperimental()->AddObserver(this); 1133 devtools_client_->GetNetwork()->Enable(); 1134 std::unique_ptr<headless::network::RequestPattern> match_all = 1135 headless::network::RequestPattern::Builder().SetUrlPattern("*").Build(); 1136 std::vector<std::unique_ptr<headless::network::RequestPattern>> patterns; 1137 patterns.push_back(std::move(match_all)); 1138 devtools_client_->GetNetwork()->GetExperimental()->SetRequestInterception( 1139 network::SetRequestInterceptionParams::Builder() 1140 .SetPatterns(std::move(patterns)) 1141 .Build()); 1142 1143 devtools_client_->GetPage()->AddObserver(this); 1144 1145 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 1146 devtools_client_->GetPage()->Enable(run_loop.QuitClosure()); 1147 run_loop.Run(); 1148 1149 devtools_client_->GetPage()->Navigate( 1150 embedded_test_server()->GetURL("/dom_tree_test.html").spec()); 1151 } 1152 OnRequestIntercepted(const network::RequestInterceptedParams & params)1153 void OnRequestIntercepted( 1154 const network::RequestInterceptedParams& params) override { 1155 if (params.HasAuthChallenge()) { 1156 auth_challenge_seen_ = true; 1157 devtools_client_->GetNetwork() 1158 ->GetExperimental() 1159 ->ContinueInterceptedRequest( 1160 network::ContinueInterceptedRequestParams::Builder() 1161 .SetInterceptionId(params.GetInterceptionId()) 1162 .SetAuthChallengeResponse( 1163 network::AuthChallengeResponse::Builder() 1164 .SetResponse(network::AuthChallengeResponseResponse:: 1165 PROVIDE_CREDENTIALS) 1166 .SetUsername("foo") // These are tested by the proxy. 1167 .SetPassword("bar") 1168 .Build()) 1169 .Build()); 1170 } else { 1171 devtools_client_->GetNetwork() 1172 ->GetExperimental() 1173 ->ContinueInterceptedRequest( 1174 network::ContinueInterceptedRequestParams::Builder() 1175 .SetInterceptionId(params.GetInterceptionId()) 1176 .Build()); 1177 GURL url(params.GetRequest()->GetUrl()); 1178 files_loaded_.insert(url.path()); 1179 } 1180 } 1181 OnLoadEventFired(const page::LoadEventFiredParams &)1182 void OnLoadEventFired(const page::LoadEventFiredParams&) override { 1183 EXPECT_TRUE(auth_challenge_seen_); 1184 EXPECT_THAT(files_loaded_, 1185 ElementsAre("/Ahem.ttf", "/dom_tree_test.css", 1186 "/dom_tree_test.html", "/iframe.html")); 1187 FinishAsynchronousTest(); 1188 } 1189 CustomizeHeadlessBrowserContext(HeadlessBrowserContext::Builder & builder)1190 void CustomizeHeadlessBrowserContext( 1191 HeadlessBrowserContext::Builder& builder) override { 1192 std::unique_ptr<net::ProxyConfig> proxy_config(new net::ProxyConfig); 1193 proxy_config->proxy_rules().ParseFromString( 1194 proxy_server_.host_port_pair().ToString()); 1195 // TODO(https://crbug.com/901896): Don't rely on proxying localhost. 1196 proxy_config->proxy_rules().bypass_rules.AddRulesToSubtractImplicit(); 1197 builder.SetProxyConfig(std::move(proxy_config)); 1198 } 1199 1200 private: 1201 net::SpawnedTestServer proxy_server_; 1202 bool auth_challenge_seen_ = false; 1203 std::set<std::string> files_loaded_; 1204 }; 1205 1206 #if defined(OS_WIN) 1207 // TODO(crbug.com/1045980): Disabled due to flakiness. 1208 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevtoolsInterceptionWithAuthProxyTest); 1209 #else 1210 HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevtoolsInterceptionWithAuthProxyTest); 1211 #endif 1212 1213 class NavigatorLanguages : public HeadlessAsyncDevTooledBrowserTest { 1214 public: RunDevTooledTest()1215 void RunDevTooledTest() override { 1216 devtools_client_->GetRuntime()->Evaluate( 1217 "JSON.stringify(navigator.languages)", 1218 base::BindOnce(&NavigatorLanguages::OnResult, base::Unretained(this))); 1219 } 1220 OnResult(std::unique_ptr<runtime::EvaluateResult> result)1221 void OnResult(std::unique_ptr<runtime::EvaluateResult> result) { 1222 EXPECT_TRUE(result->GetResult()->HasValue()); 1223 EXPECT_EQ("[\"en-UK\",\"DE\",\"FR\"]", 1224 result->GetResult()->GetValue()->GetString()); 1225 FinishAsynchronousTest(); 1226 } 1227 CustomizeHeadlessBrowserContext(HeadlessBrowserContext::Builder & builder)1228 void CustomizeHeadlessBrowserContext( 1229 HeadlessBrowserContext::Builder& builder) override { 1230 builder.SetAcceptLanguage("en-UK, DE, FR"); 1231 } 1232 }; 1233 1234 #if defined(OS_WIN) 1235 // TODO(crbug.com/1045980): Disabled due to flakiness. 1236 DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(NavigatorLanguages); 1237 #else 1238 HEADLESS_ASYNC_DEVTOOLED_TEST_F(NavigatorLanguages); 1239 #endif 1240 1241 } // namespace headless 1242