blob: c4483c89257583070976cb0483757d88b177afde [file] [log] [blame]
// 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