| // Copyright 2018 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 <lib/fidl/cpp/binding.h> |
| |
| #include "base/barrier_closure.h" |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/macros.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_piece.h" |
| #include "components/cast/message_port/message_port_fuchsia.h" |
| #include "components/cast/message_port/test_message_port_receiver.h" |
| #include "content/public/test/browser_test.h" |
| #include "fuchsia/base/fit_adapter.h" |
| #include "fuchsia/base/frame_test_util.h" |
| #include "fuchsia/base/mem_buffer_util.h" |
| #include "fuchsia/base/result_receiver.h" |
| #include "fuchsia/base/test_navigation_listener.h" |
| #include "fuchsia/engine/test/web_engine_browser_test.h" |
| #include "fuchsia/runners/cast/create_web_message.h" |
| #include "fuchsia/runners/cast/named_message_port_connector_fuchsia.h" |
| #include "testing/gmock/include/gmock/gmock-matchers.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/url_constants.h" |
| |
| using CastMessagePort = std::unique_ptr<cast_api_bindings::MessagePort>; |
| |
| namespace { |
| |
| class NamedMessagePortConnectorFuchsiaTest |
| : public cr_fuchsia::WebEngineBrowserTest { |
| public: |
| NamedMessagePortConnectorFuchsiaTest() { |
| set_test_server_root(base::FilePath("fuchsia/runners/cast/testdata")); |
| navigation_listener_.SetBeforeAckHook(base::BindRepeating( |
| &NamedMessagePortConnectorFuchsiaTest::OnBeforeAckHook, |
| base::Unretained(this))); |
| } |
| |
| ~NamedMessagePortConnectorFuchsiaTest() override = default; |
| |
| protected: |
| // BrowserTestBase implementation. |
| void SetUpOnMainThread() override { |
| cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread(); |
| frame_ = WebEngineBrowserTest::CreateFrame(&navigation_listener_); |
| connector_ = |
| std::make_unique<NamedMessagePortConnectorFuchsia>(frame_.get()); |
| } |
| |
| // Intercepts the page load event to trigger the injection of |connector_|'s |
| // services. |
| void OnBeforeAckHook( |
| const fuchsia::web::NavigationState& change, |
| fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback |
| callback) { |
| if (change.has_is_main_document_loaded() && |
| change.is_main_document_loaded()) { |
| std::string connect_message; |
| CastMessagePort connect_port; |
| connector_->GetConnectMessage(&connect_message, &connect_port); |
| frame_->PostMessage( |
| "*", CreateWebMessage(connect_message, std::move(connect_port)), |
| [](fuchsia::web::Frame_PostMessage_Result result) { |
| DCHECK(result.is_response()); |
| }); |
| } |
| |
| // Allow the TestNavigationListener's usual navigation event processing flow |
| // to continue. |
| callback(); |
| } |
| |
| std::unique_ptr<base::RunLoop> navigate_run_loop_; |
| fuchsia::web::FramePtr frame_; |
| std::unique_ptr<NamedMessagePortConnectorFuchsia> connector_; |
| cr_fuchsia::TestNavigationListener navigation_listener_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NamedMessagePortConnectorFuchsiaTest); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(NamedMessagePortConnectorFuchsiaTest, EndToEnd) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL test_url(embedded_test_server()->GetURL("/connector.html")); |
| |
| fuchsia::web::NavigationControllerPtr controller; |
| frame_->GetNavigationController(controller.NewRequest()); |
| |
| std::string received_port_name; |
| CastMessagePort received_port; |
| base::RunLoop receive_port_run_loop; |
| connector_->RegisterPortHandler(base::BindRepeating( |
| [](std::string* received_port_name, CastMessagePort* received_port, |
| base::RunLoop* receive_port_run_loop, base::StringPiece port_name, |
| CastMessagePort port) -> bool { |
| *received_port_name = std::string(port_name); |
| *received_port = std::move(port); |
| receive_port_run_loop->Quit(); |
| return true; |
| }, |
| base::Unretained(&received_port_name), base::Unretained(&received_port), |
| base::Unretained(&receive_port_run_loop))); |
| |
| EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| controller.get(), fuchsia::web::LoadUrlParams(), test_url.spec())); |
| navigation_listener_.RunUntilUrlEquals(test_url); |
| |
| // The JS code in connector.html should connect to the port "echo". |
| receive_port_run_loop.Run(); |
| EXPECT_EQ(received_port_name, "echo"); |
| |
| cast_api_bindings::TestMessagePortReceiver test_receiver; |
| received_port->SetReceiver(&test_receiver); |
| received_port->PostMessage("ping"); |
| |
| ASSERT_TRUE(test_receiver.RunUntilMessageCountEqual(3)); |
| EXPECT_EQ(test_receiver.buffer()[0].first, "early 1"); |
| EXPECT_EQ(test_receiver.buffer()[1].first, "early 2"); |
| EXPECT_EQ(test_receiver.buffer()[2].first, "ack ping"); |
| |
| EXPECT_TRUE(received_port->CanPostMessage()); |
| |
| // Ensure that the MessagePort is dropped when navigating away. |
| EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| controller.get(), fuchsia::web::LoadUrlParams(), "about:blank")); |
| |
| test_receiver.RunUntilDisconnected(); |
| EXPECT_FALSE(received_port->CanPostMessage()); |
| } |
| |
| // Tests that the NamedMessagePortConnectorFuchsia can receive more than one |
| // port over its lifetime. |
| IN_PROC_BROWSER_TEST_F(NamedMessagePortConnectorFuchsiaTest, MultiplePorts) { |
| constexpr size_t kExpectedPortCount = 3; |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL test_url( |
| embedded_test_server()->GetURL("/connector_multiple_ports.html")); |
| |
| fuchsia::web::NavigationControllerPtr controller; |
| frame_->GetNavigationController(controller.NewRequest()); |
| |
| std::vector<CastMessagePort> received_ports; |
| base::RunLoop receive_port_run_loop; |
| connector_->RegisterPortHandler(base::BindRepeating( |
| [](std::vector<CastMessagePort>* received_ports, |
| base::RunLoop* receive_port_run_loop, base::StringPiece port_name, |
| CastMessagePort port) -> bool { |
| received_ports->push_back(std::move(port)); |
| |
| if (received_ports->size() == kExpectedPortCount) |
| receive_port_run_loop->Quit(); |
| |
| return true; |
| }, |
| base::Unretained(&received_ports), |
| base::Unretained(&receive_port_run_loop))); |
| |
| EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( |
| controller.get(), fuchsia::web::LoadUrlParams(), test_url.spec())); |
| receive_port_run_loop.Run(); |
| |
| ASSERT_EQ(received_ports.size(), kExpectedPortCount); |
| for (CastMessagePort& message_port : received_ports) { |
| cast_api_bindings::TestMessagePortReceiver test_receiver; |
| message_port->SetReceiver(&test_receiver); |
| message_port->PostMessage("ping"); |
| test_receiver.RunUntilMessageCountEqual(1); |
| EXPECT_EQ(test_receiver.buffer()[0].first, "ack ping"); |
| } |
| } |
| |
| } // namespace |