1 // Copyright 2018 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 <fuchsia/web/cpp/fidl.h>
6 #include <lib/fidl/cpp/binding.h>
7
8 #include "base/barrier_closure.h"
9 #include "base/base_paths_fuchsia.h"
10 #include "base/files/file_util.h"
11 #include "base/path_service.h"
12 #include "base/test/bind.h"
13 #include "components/cast/message_port/message_port_fuchsia.h"
14 #include "content/public/test/browser_test.h"
15 #include "fuchsia/base/fit_adapter.h"
16 #include "fuchsia/base/frame_test_util.h"
17 #include "fuchsia/base/mem_buffer_util.h"
18 #include "fuchsia/base/result_receiver.h"
19 #include "fuchsia/base/test_navigation_listener.h"
20 #include "fuchsia/engine/test/web_engine_browser_test.h"
21 #include "fuchsia/runners/cast/api_bindings_client.h"
22 #include "fuchsia/runners/cast/create_web_message.h"
23 #include "fuchsia/runners/cast/named_message_port_connector_fuchsia.h"
24 #include "fuchsia/runners/cast/test_api_bindings.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace {
28
29 class ApiBindingsClientTest : public cr_fuchsia::WebEngineBrowserTest {
30 public:
ApiBindingsClientTest()31 ApiBindingsClientTest() : api_service_binding_(&api_service_) {
32 set_test_server_root(base::FilePath("fuchsia/runners/cast/testdata"));
33 }
34
35 ~ApiBindingsClientTest() override = default;
36
SetUp()37 void SetUp() override { cr_fuchsia::WebEngineBrowserTest::SetUp(); }
38
39 protected:
StartClient()40 void StartClient() {
41 base::ScopedAllowBlockingForTesting allow_blocking;
42
43 // Get the bindings from |api_service_|.
44 base::RunLoop run_loop;
45 client_ = std::make_unique<ApiBindingsClient>(
46 api_service_binding_.NewBinding(), run_loop.QuitClosure());
47 ASSERT_FALSE(client_->HasBindings());
48 run_loop.Run();
49 ASSERT_TRUE(client_->HasBindings());
50
51 frame_ = WebEngineBrowserTest::CreateFrame(&navigation_listener_);
52 frame_->GetNavigationController(controller_.NewRequest());
53 connector_ =
54 std::make_unique<NamedMessagePortConnectorFuchsia>(frame_.get());
55
56 client_->AttachToFrame(frame_.get(), connector_.get(),
57 base::MakeExpectedNotRunClosure(FROM_HERE));
58 }
59
SetUpOnMainThread()60 void SetUpOnMainThread() override {
61 cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread();
62 ASSERT_TRUE(embedded_test_server()->Start());
63 }
64
TearDownOnMainThread()65 void TearDownOnMainThread() override {
66 // Destroy |client_| before the MessageLoop is destroyed.
67 client_.reset();
68 }
69
70 fuchsia::web::FramePtr frame_;
71 std::unique_ptr<NamedMessagePortConnectorFuchsia> connector_;
72 TestApiBindings api_service_;
73 fidl::Binding<chromium::cast::ApiBindings> api_service_binding_;
74 std::unique_ptr<ApiBindingsClient> client_;
75 cr_fuchsia::TestNavigationListener navigation_listener_;
76 fuchsia::web::NavigationControllerPtr controller_;
77
78 DISALLOW_COPY_AND_ASSIGN(ApiBindingsClientTest);
79 };
80
81 // Tests API registration, injection, and message IPC.
82 // Registers a port that echoes messages received over a MessagePort back to the
83 // sender.
IN_PROC_BROWSER_TEST_F(ApiBindingsClientTest,EndToEnd)84 IN_PROC_BROWSER_TEST_F(ApiBindingsClientTest, EndToEnd) {
85 // Define the injected bindings.
86 std::vector<chromium::cast::ApiBinding> binding_list;
87 chromium::cast::ApiBinding echo_binding;
88 echo_binding.set_before_load_script(cr_fuchsia::MemBufferFromString(
89 "window.echo = cast.__platform__.PortConnector.bind('echoService');",
90 "test"));
91 binding_list.emplace_back(std::move(echo_binding));
92 api_service_.set_bindings(std::move(binding_list));
93
94 StartClient();
95
96 base::RunLoop post_message_responses_loop;
97 base::RepeatingClosure post_message_response_closure =
98 base::BarrierClosure(2, post_message_responses_loop.QuitClosure());
99
100 // Navigate to a test page that makes use of the injected bindings.
101 const GURL test_url = embedded_test_server()->GetURL("/echo.html");
102 EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
103 controller_.get(), fuchsia::web::LoadUrlParams(), test_url.spec()));
104 navigation_listener_.RunUntilUrlEquals(test_url);
105
106 std::string connect_message;
107 std::unique_ptr<cast_api_bindings::MessagePort> connect_port;
108 connector_->GetConnectMessage(&connect_message, &connect_port);
109 frame_->PostMessage(
110 "*", CreateWebMessage(connect_message, std::move(connect_port)),
111 [&post_message_response_closure](
112 fuchsia::web::Frame_PostMessage_Result result) {
113 ASSERT_TRUE(result.is_response());
114 post_message_response_closure.Run();
115 });
116
117 // Connect to the echo service hosted by the page and send a ping to it.
118 fuchsia::web::WebMessage message;
119 message.set_data(cr_fuchsia::MemBufferFromString("ping", "ping-msg"));
120 fuchsia::web::MessagePortPtr port =
121 api_service_.RunUntilMessagePortReceived("echoService").Bind();
122 port->PostMessage(std::move(message),
123 [&post_message_response_closure](
124 fuchsia::web::MessagePort_PostMessage_Result result) {
125 ASSERT_TRUE(result.is_response());
126 post_message_response_closure.Run();
127 });
128
129 // Handle the ping response.
130 base::RunLoop response_loop;
131 cr_fuchsia::ResultReceiver<fuchsia::web::WebMessage> response(
132 response_loop.QuitClosure());
133 port->ReceiveMessage(
134 cr_fuchsia::CallbackToFitFunction(response.GetReceiveCallback()));
135 response_loop.Run();
136
137 std::string response_string;
138 EXPECT_TRUE(
139 cr_fuchsia::StringFromMemBuffer(response->data(), &response_string));
140 EXPECT_EQ("ack ping", response_string);
141
142 // Ensure that we've received acks for all messages.
143 post_message_responses_loop.Run();
144 }
145
146 } // namespace
147