| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 #include "base/optional.h" |  | 
| 7 #include "base/path_service.h" |  | 
| 8 #include "base/run_loop.h" |  | 
| 9 #include "base/strings/string_piece.h" |  | 
| 10 #include "base/strings/stringprintf.h" |  | 
| 11 #include "base/threading/thread_restrictions.h" |  | 
| 12 #include "content/public/test/browser_test.h" |  | 
| 13 #include "headless/grit/headless_browsertest_resources.h" |  | 
| 14 #include "headless/lib/embedder_test.mojom.h" |  | 
| 15 #include "headless/public/devtools/domains/network.h" |  | 
| 16 #include "headless/public/devtools/domains/page.h" |  | 
| 17 #include "headless/public/devtools/domains/runtime.h" |  | 
| 18 #include "headless/public/headless_browser.h" |  | 
| 19 #include "headless/public/headless_devtools_client.h" |  | 
| 20 #include "headless/public/headless_devtools_target.h" |  | 
| 21 #include "headless/public/headless_web_contents.h" |  | 
| 22 #include "headless/test/headless_browser_test.h" |  | 
| 23 #include "mojo/public/cpp/bindings/binding_set.h" |  | 
| 24 #include "mojo/public/cpp/bindings/interface_ptr_set.h" |  | 
| 25 #include "mojo/public/cpp/bindings/interface_request.h" |  | 
| 26 #include "testing/gtest/include/gtest/gtest.h" |  | 
| 27 #include "ui/base/resource/resource_bundle.h" |  | 
| 28 #include "url/gurl.h" |  | 
| 29 |  | 
| 30 namespace headless { |  | 
| 31 |  | 
| 32 #define DEVTOOLS_CLIENT_TEST_F(TEST_FIXTURE_NAME)                        \ |  | 
| 33   IN_PROC_BROWSER_TEST_F(TEST_FIXTURE_NAME, RunAsyncTest) { RunTest(); } \ |  | 
| 34   class AsyncHeadlessBrowserTestNeedsSemicolon##TEST_FIXTURE_NAME {} |  | 
| 35 |  | 
| 36 // A test fixture which attaches a devtools client and registers a mojo |  | 
| 37 // interface before starting the test. |  | 
| 38 class EmbedderMojoTest : public HeadlessBrowserTest, |  | 
| 39                          public HeadlessWebContents::Observer, |  | 
| 40                          public embedder_test::TestEmbedderService { |  | 
| 41  public: |  | 
| 42   enum HttpPolicy { DEFAULT, ENABLE_HTTP }; |  | 
| 43 |  | 
| 44   EmbedderMojoTest() : EmbedderMojoTest(HttpPolicy::DEFAULT) {} |  | 
| 45 |  | 
| 46   explicit EmbedderMojoTest(HttpPolicy http_policy) |  | 
| 47       : browser_context_(nullptr), |  | 
| 48         web_contents_(nullptr), |  | 
| 49         devtools_client_(HeadlessDevToolsClient::Create()), |  | 
| 50         http_policy_(http_policy) {} |  | 
| 51 |  | 
| 52   ~EmbedderMojoTest() override {} |  | 
| 53 |  | 
| 54   void SetUp() override { |  | 
| 55     // Set service names before they are used during main thread initialization. |  | 
| 56     options()->mojo_service_names.insert("embedder_test::TestEmbedderService"); |  | 
| 57 |  | 
| 58     HeadlessBrowserTest::SetUp(); |  | 
| 59   } |  | 
| 60 |  | 
| 61   void SetUpOnMainThread() override { |  | 
| 62     base::ThreadRestrictions::SetIOAllowed(true); |  | 
| 63     base::FilePath pak_path; |  | 
| 64     ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &pak_path)); |  | 
| 65     pak_path = pak_path.AppendASCII("headless_browser_tests.pak"); |  | 
| 66     ResourceBundle::GetSharedInstance().AddDataPackFromPath( |  | 
| 67         pak_path, ui::SCALE_FACTOR_NONE); |  | 
| 68   } |  | 
| 69 |  | 
| 70   // HeadlessWebContents::Observer implementation: |  | 
| 71   void DevToolsTargetReady() override { |  | 
| 72     EXPECT_TRUE(web_contents_->GetDevToolsTarget()); |  | 
| 73     web_contents_->GetDevToolsTarget()->AttachClient(devtools_client_.get()); |  | 
| 74 |  | 
| 75     RunMojoTest(); |  | 
| 76   } |  | 
| 77 |  | 
| 78   virtual void RunMojoTest() = 0; |  | 
| 79 |  | 
| 80   virtual GURL GetInitialUrl() const { return GURL("about:blank"); } |  | 
| 81 |  | 
| 82   void OnEvalResult(std::unique_ptr<runtime::EvaluateResult> result) { |  | 
| 83     EXPECT_FALSE(result->HasExceptionDetails()) |  | 
| 84         << "JS exception: " << result->GetExceptionDetails()->GetText(); |  | 
| 85     if (result->HasExceptionDetails()) { |  | 
| 86       FinishAsynchronousTest(); |  | 
| 87     } |  | 
| 88   } |  | 
| 89 |  | 
| 90  protected: |  | 
| 91   void RunTest() { |  | 
| 92     // Using a pak file is idiomatic chromium style, but most embedders probably |  | 
| 93     // wouln't load the javascript bindings file this way. |  | 
| 94     std::string embedder_test_mojom_js = |  | 
| 95         ResourceBundle::GetSharedInstance() |  | 
| 96             .GetRawDataResource(IDR_HEADLESS_EMBEDDER_TEST_MOJOM_JS) |  | 
| 97             .as_string(); |  | 
| 98 |  | 
| 99     HeadlessBrowserContext::Builder builder = |  | 
| 100         browser()->CreateBrowserContextBuilder(); |  | 
| 101     builder.AddJsMojoBindings("headless/lib/embedder_test.mojom", |  | 
| 102                               embedder_test_mojom_js); |  | 
| 103     if (http_policy_ == HttpPolicy::ENABLE_HTTP) { |  | 
| 104       builder.EnableUnsafeNetworkAccessWithMojoBindings(true); |  | 
| 105     } |  | 
| 106     if (host_resolver_rules_) { |  | 
| 107       builder.SetHostResolverRules(*host_resolver_rules_); |  | 
| 108     } |  | 
| 109 |  | 
| 110     browser_context_ = builder.Build(); |  | 
| 111 |  | 
| 112     web_contents_ = |  | 
| 113         browser_context_->CreateWebContentsBuilder() |  | 
| 114             .SetInitialURL(GURL(GetInitialUrl())) |  | 
| 115             .AddMojoService(base::Bind(&EmbedderMojoTest::CreateTestMojoService, |  | 
| 116                                        base::Unretained(this))) |  | 
| 117             .Build(); |  | 
| 118 |  | 
| 119     web_contents_->AddObserver(this); |  | 
| 120     RunAsynchronousTest(); |  | 
| 121 |  | 
| 122     web_contents_->GetDevToolsTarget()->DetachClient(devtools_client_.get()); |  | 
| 123     web_contents_->RemoveObserver(this); |  | 
| 124     web_contents_->Close(); |  | 
| 125     web_contents_ = nullptr; |  | 
| 126 |  | 
| 127     browser_context_->Close(); |  | 
| 128     browser_context_ = nullptr; |  | 
| 129   } |  | 
| 130 |  | 
| 131   void CreateTestMojoService( |  | 
| 132       mojo::InterfaceRequest<embedder_test::TestEmbedderService> request) { |  | 
| 133     test_embedder_mojo_bindings_.AddBinding(this, std::move(request)); |  | 
| 134   } |  | 
| 135 |  | 
| 136   HeadlessBrowserContext* browser_context_; |  | 
| 137   HeadlessWebContents* web_contents_; |  | 
| 138   std::unique_ptr<HeadlessDevToolsClient> devtools_client_; |  | 
| 139 |  | 
| 140   mojo::BindingSet<embedder_test::TestEmbedderService> |  | 
| 141       test_embedder_mojo_bindings_; |  | 
| 142 |  | 
| 143   HttpPolicy http_policy_; |  | 
| 144   base::Optional<std::string> host_resolver_rules_; |  | 
| 145 }; |  | 
| 146 |  | 
| 147 class MojoBindingsTest : public EmbedderMojoTest { |  | 
| 148  public: |  | 
| 149   void RunMojoTest() override { |  | 
| 150     devtools_client_->GetRuntime()->Evaluate( |  | 
| 151         "// Note define() defines a module in the mojo module dependency     \n" |  | 
| 152         "// system. While we don't expose our module, the callback below only\n" |  | 
| 153         "// fires after the requested modules have been loaded.              \n" |  | 
| 154         "define([                                                            \n" |  | 
| 155         "    'headless/lib/embedder_test.mojom',                             \n" |  | 
| 156         "    'content/public/renderer/frame_interfaces',                     \n" |  | 
| 157         "    ], function(embedderMojom, frameInterfaces) {                   \n" |  | 
| 158         "  var testEmbedderService =                                         \n" |  | 
| 159         "      new embedderMojom.TestEmbedderServicePtr(                     \n" |  | 
| 160         "          frameInterfaces.getInterface(                             \n" |  | 
| 161         "              embedderMojom.TestEmbedderService.name));             \n" |  | 
| 162         "                                                                    \n" |  | 
| 163         "  // Send a message to the embedder!                                \n" |  | 
| 164         "  testEmbedderService.returnTestResult('hello world');              \n" |  | 
| 165         "});", |  | 
| 166         base::Bind(&EmbedderMojoTest::OnEvalResult, base::Unretained(this))); |  | 
| 167   } |  | 
| 168 |  | 
| 169   // embedder_test::TestEmbedderService: |  | 
| 170   void ReturnTestResult(const std::string& result) override { |  | 
| 171     EXPECT_EQ("hello world", result); |  | 
| 172     FinishAsynchronousTest(); |  | 
| 173   } |  | 
| 174 }; |  | 
| 175 |  | 
| 176 DEVTOOLS_CLIENT_TEST_F(MojoBindingsTest); |  | 
| 177 |  | 
| 178 class MojoBindingsReinstalledAfterNavigation : public EmbedderMojoTest { |  | 
| 179  public: |  | 
| 180   MojoBindingsReinstalledAfterNavigation() |  | 
| 181       : EmbedderMojoTest(HttpPolicy::ENABLE_HTTP), seen_page_one_(false) { |  | 
| 182     EXPECT_TRUE(embedded_test_server()->Start()); |  | 
| 183   } |  | 
| 184 |  | 
| 185   void SetUpOnMainThread() override { |  | 
| 186     // We want to make sure bindings work across browser initiated cross-origin |  | 
| 187     // navigation, which is why we're setting up this fake tld. |  | 
| 188     host_resolver_rules_ = |  | 
| 189         base::StringPrintf("MAP not-an-actual-domain.tld 127.0.0.1:%d", |  | 
| 190                            embedded_test_server()->host_port_pair().port()); |  | 
| 191 |  | 
| 192     EmbedderMojoTest::SetUpOnMainThread(); |  | 
| 193   } |  | 
| 194 |  | 
| 195   void RunMojoTest() override {} |  | 
| 196 |  | 
| 197   GURL GetInitialUrl() const override { |  | 
| 198     return embedded_test_server()->GetURL("/mojo_page_one.html"); |  | 
| 199   } |  | 
| 200 |  | 
| 201   // embedder_test::TestEmbedderService: |  | 
| 202   void ReturnTestResult(const std::string& result) override { |  | 
| 203     if (result == "page one") { |  | 
| 204       seen_page_one_ = true; |  | 
| 205       devtools_client_->GetPage()->Navigate( |  | 
| 206           "http://not-an-actual-domain.tld/mojo_page_two.html"); |  | 
| 207     } else { |  | 
| 208       EXPECT_TRUE(seen_page_one_); |  | 
| 209       EXPECT_EQ("page two", result); |  | 
| 210       FinishAsynchronousTest(); |  | 
| 211     } |  | 
| 212   } |  | 
| 213 |  | 
| 214  private: |  | 
| 215   bool seen_page_one_; |  | 
| 216 }; |  | 
| 217 |  | 
| 218 DEVTOOLS_CLIENT_TEST_F(MojoBindingsReinstalledAfterNavigation); |  | 
| 219 |  | 
| 220 class HttpDisabledByDefaultWhenMojoBindingsUsed : public EmbedderMojoTest, |  | 
| 221                                                   network::Observer, |  | 
| 222                                                   page::Observer { |  | 
| 223  public: |  | 
| 224   HttpDisabledByDefaultWhenMojoBindingsUsed() { |  | 
| 225     EXPECT_TRUE(embedded_test_server()->Start()); |  | 
| 226   } |  | 
| 227 |  | 
| 228   void RunMojoTest() override { |  | 
| 229     base::RunLoop run_loop; |  | 
| 230     devtools_client_->GetNetwork()->AddObserver(this); |  | 
| 231     devtools_client_->GetNetwork()->Enable(run_loop.QuitClosure()); |  | 
| 232     base::MessageLoop::ScopedNestableTaskAllower nest_loop( |  | 
| 233         base::MessageLoop::current()); |  | 
| 234     run_loop.Run(); |  | 
| 235     devtools_client_->GetPage()->AddObserver(this); |  | 
| 236     devtools_client_->GetPage()->Enable(); |  | 
| 237     devtools_client_->GetPage()->Navigate( |  | 
| 238         embedded_test_server()->GetURL("/mojo_page_one.html").spec()); |  | 
| 239   } |  | 
| 240 |  | 
| 241   void ReturnTestResult(const std::string& result) override { |  | 
| 242     DisableClientAndFinishAsynchronousTest(); |  | 
| 243     FAIL() << "The HTTP page should not have been served and we should not have" |  | 
| 244               " recieved a mojo callback!"; |  | 
| 245   } |  | 
| 246 |  | 
| 247   void OnLoadingFailed(const network::LoadingFailedParams& params) override { |  | 
| 248     // The navigation should fail since HTTP requests are blackholed. |  | 
| 249     EXPECT_EQ(params.GetErrorText(), "net::ERR_FILE_NOT_FOUND"); |  | 
| 250     DisableClientAndFinishAsynchronousTest(); |  | 
| 251   } |  | 
| 252 |  | 
| 253   void DisableClientAndFinishAsynchronousTest() { |  | 
| 254     devtools_client_->GetNetwork()->Disable(); |  | 
| 255     devtools_client_->GetNetwork()->RemoveObserver(this); |  | 
| 256     FinishAsynchronousTest(); |  | 
| 257   } |  | 
| 258 }; |  | 
| 259 |  | 
| 260 DEVTOOLS_CLIENT_TEST_F(HttpDisabledByDefaultWhenMojoBindingsUsed); |  | 
| 261 |  | 
| 262 }  // namespace headless |  | 
| OLD | NEW | 
|---|