Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Unified Diff: headless/lib/embedder_mojo_browsertest.cc

Issue 2049363003: Adds support for headless chrome embedder mojo services (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « headless/lib/browser/headless_web_contents_impl.cc ('k') | headless/lib/embedder_test.mojom » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: headless/lib/embedder_mojo_browsertest.cc
diff --git a/headless/lib/embedder_mojo_browsertest.cc b/headless/lib/embedder_mojo_browsertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..79d353f81f9e000a8aac6856aaca93290a0b9d4a
--- /dev/null
+++ b/headless/lib/embedder_mojo_browsertest.cc
@@ -0,0 +1,251 @@
+// 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/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/test/browser_test.h"
+#include "headless/grit/headless_browsertest_resources.h"
+#include "headless/lib/embedder_test.mojom.h"
+#include "headless/public/domains/network.h"
+#include "headless/public/domains/page.h"
+#include "headless/public/domains/runtime.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 "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
+
+namespace headless {
+
+#define DEVTOOLS_CLIENT_TEST_F(TEST_FIXTURE_NAME) \
+ IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \
+ class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+// A test fixture which attaches a devtools client and registers a mojo
+// interface before starting the test.
+class EmbedderMojoTest : public HeadlessBrowserTest,
+ public HeadlessWebContents::Observer,
+ public embedder_test::TestEmbedderService {
+ public:
+ enum HttpPolicy { DEFAULT, ENABLE_HTTP };
+
+ EmbedderMojoTest() : EmbedderMojoTest(HttpPolicy::DEFAULT) {}
+
+ explicit EmbedderMojoTest(HttpPolicy http_policy)
+ : web_contents_(nullptr),
+ devtools_client_(HeadlessDevToolsClient::Create()),
+ http_policy_(http_policy) {}
+
+ ~EmbedderMojoTest() override {}
+
+ void SetUpOnMainThread() override {
+ base::ThreadRestrictions::SetIOAllowed(true);
+ base::FilePath pak_path;
+ ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &pak_path));
+ pak_path = pak_path.AppendASCII("headless_browser_tests.pak");
+ ResourceBundle::GetSharedInstance().AddDataPackFromPath(
+ pak_path, ui::SCALE_FACTOR_NONE);
+ }
+
+ // HeadlessWebContentsObserver implementation:
+ void DevToolsTargetReady() override {
+ EXPECT_TRUE(web_contents_->GetDevToolsTarget());
+ web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
+
+ RunMojoTest();
+ }
+
+ virtual void RunMojoTest() = 0;
+
+ virtual GURL GetInitialUrl() const { return GURL("about:blank"); }
+
+ void OnEvalResult(std::unique_ptr<runtime::EvaluateResult> result) {
+ EXPECT_FALSE(result->HasExceptionDetails())
+ << "JS exception: " << result->GetExceptionDetails()->GetText();
+ if (result->HasExceptionDetails()) {
+ FinishAsynchronousTest();
+ }
+ }
+
+ protected:
+ void RunTest() {
+ // Using a pak file is idiomatic chromium style, but most embedders probably
+ // wouln't load the javascript bindings file this way.
+ std::string embedder_test_mojom_js =
+ ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_HEADLESS_EMBEDDER_TEST_MOJOM_JS)
+ .as_string();
+
+ if (http_policy_ == HttpPolicy::ENABLE_HTTP) {
+ browser_context_ =
+ browser()
+ ->CreateBrowserContextBuilder()
+ .AddJsMojoBindings("headless/lib/embedder_test.mojom",
+ embedder_test_mojom_js)
+ .EnableUnsafeNetworkAccessWithMojoBindings(true)
+ .Build();
+ } else {
+ browser_context_ =
+ browser()
+ ->CreateBrowserContextBuilder()
+ .AddJsMojoBindings("headless/lib/embedder_test.mojom",
+ embedder_test_mojom_js)
+ .Build();
+ }
+
+ web_contents_ =
+ browser()
+ ->CreateWebContentsBuilder()
+ .SetInitialURL(GURL(GetInitialUrl()))
+ .SetBrowserContext(browser_context_.get())
+ .AddMojoService(base::Bind(&EmbedderMojoTest::CreateTestMojoService,
+ base::Unretained(this)))
+ .Build();
+
+ web_contents_->AddObserver(this);
+ RunAsynchronousTest();
+
+ web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
+ web_contents_->RemoveObserver(this);
+ web_contents_->Close();
+ web_contents_ = nullptr;
+
+ browser_context_.reset();
+ }
+
+ void CreateTestMojoService(
+ mojo::InterfaceRequest<embedder_test::TestEmbedderService> request) {
+ test_embedder_mojo_bindings_.AddBinding(this, std::move(request));
+ }
+
+ std::unique_ptr<HeadlessBrowserContext> browser_context_;
+ HeadlessWebContents* web_contents_;
+ std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
+
+ mojo::BindingSet<embedder_test::TestEmbedderService>
+ test_embedder_mojo_bindings_;
+
+ HttpPolicy http_policy_;
+};
+
+class MojoBindingsTest : public EmbedderMojoTest {
+ public:
+ void RunMojoTest() override {
+ devtools_client_->GetRuntime()->Evaluate(
+ "// Note define() defines a module in the mojo module dependency \n"
+ "// system. While we don't expose our module, the callback below only\n"
+ "// fires after the requested modules have been loaded. \n"
+ "define([ \n"
+ " 'headless/lib/embedder_test.mojom', \n"
+ " 'mojo/public/js/core', \n"
+ " 'mojo/public/js/router', \n"
+ " 'content/public/renderer/frame_service_registry', \n"
+ " ], function(embedderMojom, mojoCore, routerModule, \n"
+ " serviceProvider) { \n"
+ " var testEmbedderService = \n"
+ " new embedderMojom.TestEmbedderService.proxyClass( \n"
+ " new routerModule.Router( \n"
+ " serviceProvider.connectToService( \n"
+ " embedderMojom.TestEmbedderService.name))); \n"
+ " \n"
+ " // Send a message to the embedder! \n"
+ " testEmbedderService.returnTestResult('hello world'); \n"
+ "});",
+ base::Bind(&EmbedderMojoTest::OnEvalResult, base::Unretained(this)));
+ }
+
+ // embedder_test::TestEmbedderService:
+ void ReturnTestResult(const std::string& result) override {
+ EXPECT_EQ("hello world", result);
+ FinishAsynchronousTest();
+ }
+};
+
+DEVTOOLS_CLIENT_TEST_F(MojoBindingsTest);
+
+class MojoBindingsReinstalledAfterNavigation : public EmbedderMojoTest {
+ public:
+ MojoBindingsReinstalledAfterNavigation()
+ : EmbedderMojoTest(HttpPolicy::ENABLE_HTTP), seen_page_one_(false) {
+ EXPECT_TRUE(embedded_test_server()->Start());
+ }
+
+ void SetUpOnMainThread() override {
+ // We want to make sure bindings work across browser initiated cross-origin
+ // navigation, which is why we're setting up this fake tld.
+ HeadlessBrowser::Options::Builder builder;
+ builder.SetHostResolverRules(
+ base::StringPrintf("MAP not-an-actual-domain.tld 127.0.0.1:%d",
+ embedded_test_server()->host_port_pair().port()));
+ SetBrowserOptions(builder.Build());
+
+ EmbedderMojoTest::SetUpOnMainThread();
+ }
+
+ void RunMojoTest() override {}
+
+ GURL GetInitialUrl() const override {
+ return embedded_test_server()->GetURL("/page_one.html");
+ }
+
+ // embedder_test::TestEmbedderService:
+ void ReturnTestResult(const std::string& result) override {
+ if (result == "page one") {
+ seen_page_one_ = true;
+ devtools_client_->GetPage()->Navigate(
+ "http://not-an-actual-domain.tld/page_two.html");
+ } else {
+ EXPECT_TRUE(seen_page_one_);
+ EXPECT_EQ("page two", result);
+ FinishAsynchronousTest();
+ }
+ }
+
+ private:
+ bool seen_page_one_;
+};
+
+DEVTOOLS_CLIENT_TEST_F(MojoBindingsReinstalledAfterNavigation);
+
+class HttpDisabledByDefaultWhenMojoBindingsUsed : public EmbedderMojoTest,
+ network::Observer,
+ page::Observer {
+ public:
+ HttpDisabledByDefaultWhenMojoBindingsUsed() {
+ EXPECT_TRUE(embedded_test_server()->Start());
+ }
+
+ void RunMojoTest() override {
+ devtools_client_->GetNetwork()->AddObserver(this);
+ devtools_client_->GetNetwork()->Enable();
+ }
+
+ GURL GetInitialUrl() const override {
+ return embedded_test_server()->GetURL("/page_one.html");
+ }
+
+ void ReturnTestResult(const std::string& result) override {
+ FinishAsynchronousTest();
+ FAIL() << "The HTTP page should not have been served and we should not have"
+ " recieved a mojo callback!";
+ }
+
+ void OnLoadingFailed(const network::LoadingFailedParams& params) override {
+ // The navigation should fail since HTTP requests are blackholed.
+ EXPECT_EQ(params.GetErrorText(), "net::ERR_FILE_NOT_FOUND");
+ FinishAsynchronousTest();
+ }
+};
+
+DEVTOOLS_CLIENT_TEST_F(HttpDisabledByDefaultWhenMojoBindingsUsed);
+
+} // namespace headless
« no previous file with comments | « headless/lib/browser/headless_web_contents_impl.cc ('k') | headless/lib/embedder_test.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698