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