| // Copyright 2020 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 "third_party/blink/public/common/messaging/web_message_port.h" |
| |
| #include "base/run_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| using Message = WebMessagePort::Message; |
| |
| class LenientMockReceiver : public WebMessagePort::MessageReceiver { |
| public: |
| LenientMockReceiver() = default; |
| ~LenientMockReceiver() override = default; |
| |
| // WebMessagePort::MessageReceiver implementation: |
| MOCK_METHOD1(OnMessage, bool(Message)); |
| MOCK_METHOD0(OnPipeError, void()); |
| }; |
| |
| using MockReceiver = testing::StrictMock<LenientMockReceiver>; |
| |
| using testing::_; |
| using testing::Invoke; |
| |
| } // namespace |
| |
| TEST(WebMessagePortTest, EndToEnd) { |
| base::test::SingleThreadTaskEnvironment task_env; |
| |
| // Create a dummy pipe and ensure it behaves as expected. |
| WebMessagePort port0; |
| EXPECT_FALSE(port0.IsValid()); |
| EXPECT_FALSE(port0.is_errored()); |
| EXPECT_TRUE(port0.is_closed()); |
| EXPECT_FALSE(port0.is_transferable()); |
| EXPECT_FALSE(port0.HasReceiver()); |
| EXPECT_FALSE(port0.CanPostMessage()); |
| |
| // Create a pipe. |
| auto pipe = WebMessagePort::CreatePair(); |
| port0 = std::move(pipe.first); |
| WebMessagePort port1 = std::move(pipe.second); |
| |
| EXPECT_TRUE(port0.IsValid()); |
| EXPECT_FALSE(port0.is_errored()); |
| EXPECT_FALSE(port0.is_closed()); |
| EXPECT_TRUE(port0.is_transferable()); |
| EXPECT_FALSE(port0.HasReceiver()); |
| EXPECT_FALSE(port0.CanPostMessage()); |
| EXPECT_TRUE(port1.IsValid()); |
| EXPECT_FALSE(port1.is_errored()); |
| EXPECT_FALSE(port1.is_closed()); |
| EXPECT_TRUE(port1.is_transferable()); |
| EXPECT_FALSE(port1.HasReceiver()); |
| EXPECT_FALSE(port1.CanPostMessage()); |
| |
| // And bind both endpoints to distinct receivers. The ports should remain |
| // valid but no longer be transferable. |
| MockReceiver receiver0; |
| MockReceiver receiver1; |
| port0.SetReceiver(&receiver0, task_env.GetMainThreadTaskRunner()); |
| port1.SetReceiver(&receiver1, task_env.GetMainThreadTaskRunner()); |
| |
| EXPECT_TRUE(port0.IsValid()); |
| EXPECT_FALSE(port0.is_errored()); |
| EXPECT_FALSE(port0.is_closed()); |
| EXPECT_FALSE(port0.is_transferable()); |
| EXPECT_TRUE(port0.HasReceiver()); |
| EXPECT_TRUE(port0.CanPostMessage()); |
| EXPECT_TRUE(port1.IsValid()); |
| EXPECT_FALSE(port1.is_errored()); |
| EXPECT_FALSE(port1.is_closed()); |
| EXPECT_FALSE(port1.is_transferable()); |
| EXPECT_TRUE(port1.HasReceiver()); |
| EXPECT_TRUE(port1.CanPostMessage()); |
| |
| // Send a simple string-only message one way from port 0 to port 1. |
| base::string16 message(base::UTF8ToUTF16("foo")); |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(receiver1, OnMessage(_)) |
| .WillOnce( |
| Invoke([&message, &run_loop](Message&& received_message) -> bool { |
| EXPECT_EQ(message, received_message.data); |
| EXPECT_TRUE(received_message.ports.empty()); |
| run_loop.Quit(); |
| return true; |
| })); |
| port0.PostMessage(Message(message)); |
| run_loop.Run(); |
| testing::Mock::VerifyAndClearExpectations(&receiver0); |
| testing::Mock::VerifyAndClearExpectations(&receiver1); |
| } |
| |
| // Send a message the other way (from 1 to 0) with a port. |
| auto pipe2 = WebMessagePort::CreatePair(); |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(receiver0, OnMessage(_)) |
| .WillOnce( |
| Invoke([&message, &run_loop](Message&& received_message) -> bool { |
| EXPECT_EQ(message, received_message.data); |
| EXPECT_EQ(1u, received_message.ports.size()); |
| run_loop.Quit(); |
| return true; |
| })); |
| port1.PostMessage(Message(message, std::move(pipe2.first))); |
| run_loop.Run(); |
| testing::Mock::VerifyAndClearExpectations(&receiver0); |
| testing::Mock::VerifyAndClearExpectations(&receiver1); |
| } |
| |
| // Close one end of the pipe and expect the other end to get an error. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(receiver1, OnPipeError()).WillOnce(Invoke([&run_loop]() { |
| run_loop.Quit(); |
| })); |
| port0.Close(); |
| EXPECT_FALSE(port0.IsValid()); |
| EXPECT_FALSE(port0.is_errored()); |
| EXPECT_TRUE(port0.is_closed()); |
| EXPECT_FALSE(port0.is_transferable()); |
| EXPECT_FALSE(port0.HasReceiver()); |
| EXPECT_FALSE(port0.CanPostMessage()); |
| run_loop.Run(); |
| EXPECT_TRUE(port1.IsValid()); |
| EXPECT_TRUE(port1.is_errored()); |
| EXPECT_FALSE(port1.is_closed()); |
| EXPECT_FALSE(port1.is_transferable()); |
| EXPECT_TRUE(port1.HasReceiver()); |
| EXPECT_FALSE(port1.CanPostMessage()); |
| testing::Mock::VerifyAndClearExpectations(&receiver0); |
| testing::Mock::VerifyAndClearExpectations(&receiver1); |
| } |
| |
| // Reset the pipe and expect it to go back to a fully default state. |
| port1.Reset(); |
| EXPECT_FALSE(port1.IsValid()); |
| EXPECT_FALSE(port1.is_errored()); |
| EXPECT_TRUE(port1.is_closed()); |
| EXPECT_FALSE(port1.is_transferable()); |
| EXPECT_FALSE(port1.HasReceiver()); |
| EXPECT_FALSE(port1.CanPostMessage()); |
| } |
| |
| TEST(WebMessagePortTest, MoveAssignToConnectedPort) { |
| base::test::SingleThreadTaskEnvironment task_env; |
| |
| // Create a pipe. |
| auto pipe = WebMessagePort::CreatePair(); |
| WebMessagePort port0 = std::move(pipe.first); |
| WebMessagePort port1 = std::move(pipe.second); |
| |
| // And bind both endpoints to distinct receivers. |
| MockReceiver receiver0; |
| MockReceiver receiver1; |
| port0.SetReceiver(&receiver0, task_env.GetMainThreadTaskRunner()); |
| port1.SetReceiver(&receiver1, task_env.GetMainThreadTaskRunner()); |
| |
| // Move assign a new port into the open one. This should result in the |
| // open port being closed, which can be noticed on the remote half as a |
| // connection error. |
| base::RunLoop run_loop; |
| EXPECT_CALL(receiver1, OnPipeError()).WillOnce(Invoke([&run_loop]() { |
| run_loop.Quit(); |
| })); |
| |
| port0 = WebMessagePort(); |
| |
| run_loop.Run(); |
| testing::Mock::VerifyAndClearExpectations(&receiver0); |
| testing::Mock::VerifyAndClearExpectations(&receiver1); |
| } |
| |
| } // namespace blink |