| // Copyright 2019 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 <fuchsia/web/cpp/fidl.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/sys/cpp/component_context.h> |
| |
| #include "base/fuchsia/default_context.h" |
| #include "base/fuchsia/file_utils.h" |
| #include "base/fuchsia/fuchsia_logging.h" |
| #include "base/fuchsia/service_directory_client.h" |
| #include "base/macros.h" |
| #include "base/path_service.h" |
| #include "base/test/task_environment.h" |
| #include "fuchsia/base/fit_adapter.h" |
| #include "fuchsia/base/frame_test_util.h" |
| #include "fuchsia/base/result_receiver.h" |
| #include "fuchsia/base/test_devtools_list_fetcher.h" |
| #include "fuchsia/base/test_navigation_listener.h" |
| #include "net/http/http_request_headers.h" |
| #include "net/test/embedded_test_server/default_handlers.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| constexpr char kValidUserAgentProduct[] = "TestProduct"; |
| constexpr char kValidUserAgentVersion[] = "dev.12345"; |
| constexpr char kValidUserAgentProductAndVersion[] = "TestProduct/dev.12345"; |
| constexpr char kInvalidUserAgentProduct[] = "Test/Product"; |
| constexpr char kInvalidUserAgentVersion[] = "dev/12345"; |
| |
| } // namespace |
| |
| class WebEngineIntegrationTest : public testing::Test { |
| public: |
| WebEngineIntegrationTest() |
| : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {} |
| ~WebEngineIntegrationTest() override = default; |
| |
| void SetUp() override { |
| web_context_provider_ = base::fuchsia::ComponentContextForCurrentProcess() |
| ->svc() |
| ->Connect<fuchsia::web::ContextProvider>(); |
| web_context_provider_.set_error_handler( |
| [](zx_status_t status) { ADD_FAILURE(); }); |
| |
| net::test_server::RegisterDefaultHandlers(&embedded_test_server_); |
| ASSERT_TRUE(embedded_test_server_.Start()); |
| } |
| |
| fuchsia::web::CreateContextParams DefaultContextParams() const { |
| fuchsia::web::CreateContextParams create_params; |
| auto directory = base::fuchsia::OpenDirectory( |
| base::FilePath(base::fuchsia::kServiceDirectoryPath)); |
| EXPECT_TRUE(directory.is_valid()); |
| create_params.set_service_directory(std::move(directory)); |
| return create_params; |
| } |
| |
| void CreateContextAndFrame(fuchsia::web::CreateContextParams params) { |
| web_context_provider_->Create(std::move(params), context_.NewRequest()); |
| context_.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| context_->CreateFrame(frame_.NewRequest()); |
| frame_.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| frame_->GetNavigationController(navigation_controller_.NewRequest()); |
| navigation_controller_.set_error_handler( |
| [](zx_status_t status) { ADD_FAILURE(); }); |
| } |
| |
| void CreateContextAndExpectError(fuchsia::web::CreateContextParams params, |
| zx_status_t expected_error) { |
| web_context_provider_->Create(std::move(params), context_.NewRequest()); |
| base::RunLoop run_loop; |
| context_.set_error_handler([&run_loop, expected_error](zx_status_t status) { |
| EXPECT_EQ(status, expected_error); |
| run_loop.Quit(); |
| }); |
| run_loop.Run(); |
| } |
| |
| void CreateContextAndFrameAndLoadUrl(fuchsia::web::CreateContextParams params, |
| const GURL& url) { |
| CreateContextAndFrame(std::move(params)); |
| |
| // Attach a navigation listener, to monitor the state of the Frame. |
| cr_fuchsia::TestNavigationListener listener; |
| fidl::Binding<fuchsia::web::NavigationEventListener> listener_binding( |
| &listener); |
| frame_->SetNavigationEventListener(listener_binding.NewBinding()); |
| |
| // Navigate the Frame to |url| and wait for it to complete loading. |
| fuchsia::web::LoadUrlParams load_url_params; |
| ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| navigation_controller_.get(), std::move(load_url_params), url.spec())); |
| |
| // Wait for the URL to finish loading. |
| listener.RunUntilUrlEquals(url); |
| } |
| |
| std::string ExecuteJavaScriptWithStringResult(base::StringPiece script) { |
| base::Optional<base::Value> value = |
| cr_fuchsia::ExecuteJavaScript(frame_.get(), script); |
| return value ? value->GetString() : std::string(); |
| } |
| |
| fidl::InterfaceHandle<fuchsia::io::Directory> OpenDirectoryHandle( |
| const base::FilePath& path) { |
| fidl::InterfaceHandle<fuchsia::io::Directory> directory_channel; |
| zx_status_t status = fdio_open( |
| path.value().c_str(), |
| fuchsia::io::OPEN_FLAG_DIRECTORY | fuchsia::io::OPEN_RIGHT_READABLE, |
| directory_channel.NewRequest().TakeChannel().release()); |
| ZX_DCHECK(status == ZX_OK, status) << "fdio_open"; |
| return directory_channel; |
| } |
| |
| protected: |
| const base::test::TaskEnvironment task_environment_; |
| |
| fuchsia::web::ContextProviderPtr web_context_provider_; |
| |
| net::EmbeddedTestServer embedded_test_server_; |
| |
| fuchsia::web::ContextPtr context_; |
| fuchsia::web::FramePtr frame_; |
| fuchsia::web::NavigationControllerPtr navigation_controller_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebEngineIntegrationTest); |
| }; |
| |
| TEST_F(WebEngineIntegrationTest, ValidUserAgent) { |
| const std::string kEchoHeaderPath = |
| std::string("/echoheader?") + net::HttpRequestHeaders::kUserAgent; |
| const GURL kEchoUserAgentUrl(embedded_test_server_.GetURL(kEchoHeaderPath)); |
| |
| { |
| // Create a Context with just an embedder product specified. |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| create_params.set_user_agent_product(kValidUserAgentProduct); |
| CreateContextAndFrameAndLoadUrl(std::move(create_params), |
| kEchoUserAgentUrl); |
| |
| // Query & verify that the header echoed into the document body contains |
| // the product tag. |
| std::string result = |
| ExecuteJavaScriptWithStringResult("document.body.innerText;"); |
| EXPECT_TRUE(result.find(kValidUserAgentProduct) != std::string::npos); |
| |
| // Query & verify that the navigator.userAgent contains the product tag. |
| result = ExecuteJavaScriptWithStringResult("navigator.userAgent;"); |
| EXPECT_TRUE(result.find(kValidUserAgentProduct) != std::string::npos); |
| } |
| |
| { |
| // Create a Context with both product and version specified. |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| create_params.set_user_agent_product(kValidUserAgentProduct); |
| create_params.set_user_agent_version(kValidUserAgentVersion); |
| CreateContextAndFrameAndLoadUrl(std::move(create_params), |
| kEchoUserAgentUrl); |
| |
| // Query & verify that the header echoed into the document body contains |
| // both product & version. |
| std::string result = |
| ExecuteJavaScriptWithStringResult("document.body.innerText;"); |
| EXPECT_TRUE(result.find(kValidUserAgentProductAndVersion) != |
| std::string::npos); |
| |
| // Query & verify that the navigator.userAgent contains product & version. |
| result = ExecuteJavaScriptWithStringResult("navigator.userAgent;"); |
| EXPECT_TRUE(result.find(kValidUserAgentProductAndVersion) != |
| std::string::npos); |
| } |
| } |
| |
| TEST_F(WebEngineIntegrationTest, InvalidUserAgent) { |
| const std::string kEchoHeaderPath = |
| std::string("/echoheader?") + net::HttpRequestHeaders::kUserAgent; |
| const GURL kEchoUserAgentUrl(embedded_test_server_.GetURL(kEchoHeaderPath)); |
| |
| { |
| // Try to create a Context with an invalid embedder product tag. |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| create_params.set_user_agent_product(kInvalidUserAgentProduct); |
| CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS); |
| } |
| |
| { |
| // Try to create a Context with an embedder version but no product. |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| create_params.set_user_agent_version(kValidUserAgentVersion); |
| CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS); |
| } |
| |
| { |
| // Try to create a Context with valid product tag, but invalid version. |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| create_params.set_user_agent_product(kValidUserAgentProduct); |
| create_params.set_user_agent_version(kInvalidUserAgentVersion); |
| CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS); |
| } |
| } |
| |
| // Check the remote_debugging_port parameter in CreateContextParams properly |
| // opens the DevTools service in the created Context. |
| // Check Context.GetRemoteDebuggingPort() API is not blocking. |
| TEST_F(WebEngineIntegrationTest, RemoteDebuggingPort) { |
| fuchsia::web::CreateContextParams create_params; |
| auto directory = base::fuchsia::OpenDirectory( |
| base::FilePath(base::fuchsia::kServiceDirectoryPath)); |
| ASSERT_TRUE(directory.is_valid()); |
| create_params.set_service_directory(std::move(directory)); |
| create_params.set_remote_debugging_port(0); |
| |
| // Create Context, Frame and NavigationController. |
| fuchsia::web::ContextPtr web_context; |
| web_context_provider_->Create(std::move(create_params), |
| web_context.NewRequest()); |
| web_context.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| // Get the remote debugging port early, to ensure this is not blocking. |
| base::RunLoop run_loop; |
| cr_fuchsia::ResultReceiver< |
| fuchsia::web::Context_GetRemoteDebuggingPort_Result> |
| port_receiver(run_loop.QuitClosure()); |
| web_context->GetRemoteDebuggingPort( |
| cr_fuchsia::CallbackToFitFunction(port_receiver.GetReceiveCallback())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(port_receiver->is_response()); |
| uint16_t remote_debugging_port = port_receiver->response().port; |
| ASSERT_TRUE(remote_debugging_port != 0); |
| |
| fuchsia::web::FramePtr web_frame; |
| web_context->CreateFrame(web_frame.NewRequest()); |
| web_frame.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| fuchsia::web::NavigationControllerPtr nav_controller; |
| web_frame->GetNavigationController(nav_controller.NewRequest()); |
| nav_controller.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| cr_fuchsia::TestNavigationListener navigation_listener; |
| fidl::Binding<fuchsia::web::NavigationEventListener> listener_binding( |
| &navigation_listener); |
| web_frame->SetNavigationEventListener(listener_binding.NewBinding()); |
| |
| GURL url = embedded_test_server_.GetURL("/defaultresponse"); |
| ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| nav_controller.get(), fuchsia::web::LoadUrlParams(), url.spec())); |
| navigation_listener.RunUntilUrlEquals(url); |
| |
| base::Value devtools_list = |
| cr_fuchsia::GetDevToolsListFromPort(remote_debugging_port); |
| ASSERT_TRUE(devtools_list.is_list()); |
| EXPECT_EQ(devtools_list.GetList().size(), 1u); |
| |
| base::Value* devtools_url = devtools_list.GetList()[0].FindPath("url"); |
| ASSERT_TRUE(devtools_url->is_string()); |
| EXPECT_EQ(devtools_url->GetString(), url); |
| } |
| |
| // Navigates to a resource served under the "testdata" ContentDirectory. |
| TEST_F(WebEngineIntegrationTest, ContentDirectoryProvider) { |
| const GURL kUrl("fuchsia-dir://testdata/title1.html"); |
| constexpr char kTitle[] = "title 1"; |
| |
| fuchsia::web::CreateContextParams create_params = DefaultContextParams(); |
| |
| fuchsia::web::ContentDirectoryProvider provider; |
| provider.set_name("testdata"); |
| base::FilePath pkg_path; |
| CHECK(base::PathService::Get(base::DIR_ASSETS, &pkg_path)); |
| provider.set_directory( |
| OpenDirectoryHandle(pkg_path.AppendASCII("fuchsia/engine/test/data"))); |
| |
| create_params.mutable_content_directories()->emplace_back( |
| std::move(provider)); |
| |
| CreateContextAndFrame(std::move(create_params)); |
| |
| fuchsia::web::NavigationControllerPtr controller; |
| frame_->GetNavigationController(controller.NewRequest()); |
| controller.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); |
| |
| // Navigate to test1.html and verify that the resource was correctly |
| // downloaded and interpreted by inspecting the document title. |
| EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec())); |
| cr_fuchsia::TestNavigationListener navigation_listener; |
| fidl::Binding<fuchsia::web::NavigationEventListener> listener_binding( |
| &navigation_listener); |
| frame_->SetNavigationEventListener(listener_binding.NewBinding()); |
| navigation_listener.RunUntilUrlAndTitleEquals(kUrl, kTitle); |
| } |