| // 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 "headless/test/headless_browser_test.h" |
| |
| #include "base/files/file_path.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/common/url_constants.h" |
| #include "headless/lib/browser/headless_browser_impl.h" |
| #include "headless/lib/headless_content_main_delegate.h" |
| #include "headless/public/domains/network.h" |
| #include "headless/public/domains/page.h" |
| #include "headless/public/domains/runtime.h" |
| #include "headless/public/headless_devtools_client.h" |
| #include "headless/public/headless_devtools_target.h" |
| #include "headless/public/headless_web_contents.h" |
| |
| namespace headless { |
| namespace { |
| |
| class WaitForLoadObserver : public page::Observer, public network::Observer { |
| public: |
| WaitForLoadObserver(HeadlessBrowserTest* browser_test, |
| HeadlessWebContents* web_contents) |
| : browser_test_(browser_test), |
| web_contents_(web_contents), |
| devtools_client_(HeadlessDevToolsClient::Create()), |
| navigation_succeeded_(true) { |
| web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
| devtools_client_->GetNetwork()->AddObserver(this); |
| devtools_client_->GetNetwork()->Enable(); |
| devtools_client_->GetPage()->AddObserver(this); |
| devtools_client_->GetPage()->Enable(); |
| } |
| |
| ~WaitForLoadObserver() override { |
| devtools_client_->GetNetwork()->RemoveObserver(this); |
| devtools_client_->GetPage()->RemoveObserver(this); |
| web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); |
| } |
| |
| void OnLoadEventFired(const page::LoadEventFiredParams& params) override { |
| browser_test_->FinishAsynchronousTest(); |
| } |
| |
| void OnResponseReceived( |
| const network::ResponseReceivedParams& params) override { |
| if (params.GetResponse()->GetStatus() != 200 || |
| params.GetResponse()->GetUrl() == content::kUnreachableWebDataURL) { |
| navigation_succeeded_ = false; |
| } |
| } |
| |
| bool navigation_succeeded() const { return navigation_succeeded_; } |
| |
| private: |
| HeadlessBrowserTest* browser_test_; // Not owned. |
| HeadlessWebContents* web_contents_; // Not owned. |
| std::unique_ptr<HeadlessDevToolsClient> devtools_client_; |
| |
| bool navigation_succeeded_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WaitForLoadObserver); |
| }; |
| |
| class EvaluateHelper { |
| public: |
| EvaluateHelper(HeadlessBrowserTest* browser_test, |
| HeadlessWebContents* web_contents, |
| const std::string& script_to_eval) |
| : browser_test_(browser_test), |
| web_contents_(web_contents), |
| devtools_client_(HeadlessDevToolsClient::Create()) { |
| web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |
| devtools_client_->GetRuntime()->Evaluate( |
| script_to_eval, |
| base::Bind(&EvaluateHelper::OnEvaluateResult, base::Unretained(this))); |
| } |
| |
| ~EvaluateHelper() { |
| web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); |
| } |
| |
| void OnEvaluateResult(std::unique_ptr<runtime::EvaluateResult> result) { |
| result_ = std::move(result); |
| browser_test_->FinishAsynchronousTest(); |
| } |
| |
| std::unique_ptr<runtime::EvaluateResult> 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<runtime::EvaluateResult> result_; |
| |
| DISALLOW_COPY_AND_ASSIGN(EvaluateHelper); |
| }; |
| |
| } // namespace |
| |
| HeadlessBrowserTest::HeadlessBrowserTest() { |
| base::FilePath headless_test_data(FILE_PATH_LITERAL("headless/test/data")); |
| CreateTestServer(headless_test_data); |
| } |
| |
| HeadlessBrowserTest::~HeadlessBrowserTest() {} |
| |
| void HeadlessBrowserTest::SetUpOnMainThread() {} |
| |
| void HeadlessBrowserTest::TearDownOnMainThread() { |
| browser()->Shutdown(); |
| } |
| |
| void HeadlessBrowserTest::RunTestOnMainThreadLoop() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| |
| // Pump startup related events. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| SetUpOnMainThread(); |
| RunTestOnMainThread(); |
| TearDownOnMainThread(); |
| |
| for (content::RenderProcessHost::iterator i( |
| content::RenderProcessHost::AllHostsIterator()); |
| !i.IsAtEnd(); i.Advance()) { |
| i.GetCurrentValue()->FastShutdownIfPossible(); |
| } |
| } |
| |
| void HeadlessBrowserTest::SetBrowserOptions(HeadlessBrowser::Options options) { |
| HeadlessContentMainDelegate::GetInstance()->browser()->SetOptionsForTesting( |
| std::move(options)); |
| } |
| |
| HeadlessBrowser* HeadlessBrowserTest::browser() const { |
| return HeadlessContentMainDelegate::GetInstance()->browser(); |
| } |
| |
| bool HeadlessBrowserTest::WaitForLoad(HeadlessWebContents* web_contents) { |
| WaitForLoadObserver observer(this, web_contents); |
| RunAsynchronousTest(); |
| return observer.navigation_succeeded(); |
| } |
| |
| std::unique_ptr<runtime::EvaluateResult> HeadlessBrowserTest::EvaluateScript( |
| HeadlessWebContents* web_contents, |
| const std::string& script) { |
| EvaluateHelper helper(this, web_contents, script); |
| RunAsynchronousTest(); |
| return helper.TakeResult(); |
| } |
| |
| void HeadlessBrowserTest::RunAsynchronousTest() { |
| base::MessageLoop::ScopedNestableTaskAllower nestable_allower( |
| base::MessageLoop::current()); |
| EXPECT_FALSE(run_loop_); |
| run_loop_ = base::WrapUnique(new base::RunLoop()); |
| run_loop_->Run(); |
| run_loop_ = nullptr; |
| } |
| |
| void HeadlessBrowserTest::FinishAsynchronousTest() { |
| run_loop_->Quit(); |
| } |
| |
| } // namespace headless |