You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
367 lines
16 KiB
367 lines
16 KiB
// 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 "osp/public/message_demuxer.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include "osp/msgs/osp_messages.h"
|
|
#include "osp/public/testing/message_demuxer_test_support.h"
|
|
#include "platform/test/fake_clock.h"
|
|
#include "third_party/tinycbor/src/src/cbor.h"
|
|
|
|
namespace openscreen {
|
|
namespace osp {
|
|
namespace {
|
|
|
|
using ::testing::_;
|
|
using ::testing::Invoke;
|
|
|
|
ErrorOr<size_t> ConvertDecodeResult(ssize_t result) {
|
|
if (result < 0) {
|
|
if (result == -CborErrorUnexpectedEOF)
|
|
return Error::Code::kCborIncompleteMessage;
|
|
else
|
|
return Error::Code::kCborParsing;
|
|
} else {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class MessageDemuxerTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
ASSERT_TRUE(
|
|
msgs::EncodePresentationConnectionOpenRequest(request_, &buffer_));
|
|
}
|
|
|
|
void ExpectDecodedRequest(
|
|
ssize_t decode_result,
|
|
const msgs::PresentationConnectionOpenRequest& received_request) {
|
|
ASSERT_GT(decode_result, 0);
|
|
EXPECT_EQ(decode_result, static_cast<ssize_t>(buffer_.size() - 2));
|
|
EXPECT_EQ(request_.request_id, received_request.request_id);
|
|
EXPECT_EQ(request_.presentation_id, received_request.presentation_id);
|
|
EXPECT_EQ(request_.url, received_request.url);
|
|
}
|
|
|
|
const uint64_t endpoint_id_ = 13;
|
|
const uint64_t connection_id_ = 45;
|
|
FakeClock fake_clock_{Clock::time_point(std::chrono::milliseconds(1298424))};
|
|
msgs::CborEncodeBuffer buffer_;
|
|
msgs::PresentationConnectionOpenRequest request_{1, "fry-am-the-egg-man",
|
|
"url"};
|
|
MockMessageCallback mock_callback_;
|
|
MessageDemuxer demuxer_{FakeClock::now, MessageDemuxer::kDefaultBufferLimit};
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(MessageDemuxerTest, WatchStartStop) {
|
|
MessageDemuxer::MessageWatch watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
EXPECT_CALL(mock_callback_, OnStreamMessage(_, _, _, _, _, _)).Times(0);
|
|
demuxer_.OnStreamData(endpoint_id_ + 1, 14, buffer_.data(), buffer_.size());
|
|
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
|
|
watch = MessageDemuxer::MessageWatch();
|
|
EXPECT_CALL(mock_callback_, OnStreamMessage(_, _, _, _, _, _)).Times(0);
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, BufferPartialMessage) {
|
|
MockMessageCallback mock_callback_;
|
|
constexpr uint64_t endpoint_id_ = 13;
|
|
|
|
MessageDemuxer::MessageWatch watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.Times(2)
|
|
.WillRepeatedly(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size() - 3);
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_,
|
|
buffer_.data() + buffer_.size() - 3, 3);
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, DefaultWatch) {
|
|
MockMessageCallback mock_callback_;
|
|
constexpr uint64_t endpoint_id_ = 13;
|
|
|
|
MessageDemuxer::MessageWatch watch = demuxer_.SetDefaultMessageTypeWatch(
|
|
msgs::Type::kPresentationConnectionOpenRequest, &mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, DefaultWatchOverridden) {
|
|
MockMessageCallback mock_callback_global;
|
|
MockMessageCallback mock_callback_;
|
|
constexpr uint64_t endpoint_id_ = 13;
|
|
|
|
MessageDemuxer::MessageWatch default_watch =
|
|
demuxer_.SetDefaultMessageTypeWatch(
|
|
msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_global);
|
|
ASSERT_TRUE(default_watch);
|
|
MessageDemuxer::MessageWatch watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(mock_callback_, OnStreamMessage(_, _, _, _, _, _)).Times(0);
|
|
EXPECT_CALL(
|
|
mock_callback_global,
|
|
OnStreamMessage(endpoint_id_ + 1, 14,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer_.OnStreamData(endpoint_id_ + 1, 14, buffer_.data(), buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
|
|
decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, WatchAfterData) {
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
MessageDemuxer::MessageWatch watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, WatchAfterMultipleData) {
|
|
MockMessageCallback mock_init_callback;
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
msgs::PresentationStartRequest received_init_request;
|
|
ssize_t decode_result1 = 0;
|
|
ssize_t decode_result2 = 0;
|
|
MessageDemuxer::MessageWatch init_watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationStartRequest, &mock_init_callback);
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result1, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result1 = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result1);
|
|
}));
|
|
EXPECT_CALL(mock_init_callback,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationStartRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result2, &received_init_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result2 = msgs::DecodePresentationStartRequest(
|
|
buffer, buffer_size, &received_init_request);
|
|
return ConvertDecodeResult(decode_result2);
|
|
}));
|
|
MessageDemuxer::MessageWatch watch = demuxer_.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
|
|
msgs::CborEncodeBuffer buffer;
|
|
msgs::PresentationStartRequest request;
|
|
request.request_id = 2;
|
|
request.url = "https://example.com/recv";
|
|
ASSERT_TRUE(msgs::EncodePresentationStartRequest(request, &buffer));
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer.data(),
|
|
buffer.size());
|
|
|
|
ExpectDecodedRequest(decode_result1, received_request);
|
|
ASSERT_GT(decode_result2, 0);
|
|
EXPECT_EQ(decode_result2, static_cast<ssize_t>(buffer.size() - 2));
|
|
EXPECT_EQ(request.request_id, received_init_request.request_id);
|
|
EXPECT_EQ(request.url, received_init_request.url);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, GlobalWatchAfterData) {
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
MessageDemuxer::MessageWatch watch = demuxer_.SetDefaultMessageTypeWatch(
|
|
msgs::Type::kPresentationConnectionOpenRequest, &mock_callback_);
|
|
ASSERT_TRUE(watch);
|
|
demuxer_.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, BufferLimit) {
|
|
MessageDemuxer demuxer(FakeClock::now, 10);
|
|
|
|
demuxer.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
EXPECT_CALL(mock_callback_, OnStreamMessage(_, _, _, _, _, _)).Times(0);
|
|
MessageDemuxer::MessageWatch watch = demuxer.WatchMessageType(
|
|
endpoint_id_, msgs::Type::kPresentationConnectionOpenRequest,
|
|
&mock_callback_);
|
|
|
|
msgs::PresentationConnectionOpenRequest received_request;
|
|
ssize_t decode_result = 0;
|
|
EXPECT_CALL(
|
|
mock_callback_,
|
|
OnStreamMessage(endpoint_id_, connection_id_,
|
|
msgs::Type::kPresentationConnectionOpenRequest, _, _, _))
|
|
.WillOnce(Invoke([&decode_result, &received_request](
|
|
uint64_t endpoint_id, uint64_t connection_id,
|
|
msgs::Type message_type, const uint8_t* buffer,
|
|
size_t buffer_size, Clock::time_point now) {
|
|
decode_result = msgs::DecodePresentationConnectionOpenRequest(
|
|
buffer, buffer_size, &received_request);
|
|
return ConvertDecodeResult(decode_result);
|
|
}));
|
|
demuxer.OnStreamData(endpoint_id_, connection_id_, buffer_.data(),
|
|
buffer_.size());
|
|
ExpectDecodedRequest(decode_result, received_request);
|
|
}
|
|
|
|
TEST_F(MessageDemuxerTest, DeserializeMessages) {
|
|
std::vector<uint8_t> kAgentInfoResponseSerialized{0x0B, 0xFF};
|
|
std::vector<uint8_t> kPresentationConnectionCloseEventSerialized{0x40, 0x71,
|
|
0x00};
|
|
std::vector<uint8_t> kAuthenticationRequestSerialized{0x43, 0xE9, 0xFF, 0x00};
|
|
|
|
size_t used_bytes;
|
|
auto kAgentInfoResponseInfo =
|
|
MessageTypeDecoder::DecodeType(kAgentInfoResponseSerialized, &used_bytes);
|
|
EXPECT_FALSE(kAgentInfoResponseInfo.is_error());
|
|
EXPECT_EQ(used_bytes, size_t{1});
|
|
EXPECT_EQ(kAgentInfoResponseInfo.value(), msgs::Type::kAgentInfoResponse);
|
|
|
|
auto kPresentationConnectionCloseEventInfo = MessageTypeDecoder::DecodeType(
|
|
kPresentationConnectionCloseEventSerialized, &used_bytes);
|
|
EXPECT_FALSE(kPresentationConnectionCloseEventInfo.is_error());
|
|
EXPECT_EQ(used_bytes, size_t{2});
|
|
EXPECT_EQ(kPresentationConnectionCloseEventInfo.value(),
|
|
msgs::Type::kPresentationConnectionCloseEvent);
|
|
|
|
auto kAuthenticationRequestInfo = MessageTypeDecoder::DecodeType(
|
|
kAuthenticationRequestSerialized, &used_bytes);
|
|
EXPECT_FALSE(kAuthenticationRequestInfo.is_error());
|
|
EXPECT_EQ(used_bytes, size_t{2});
|
|
EXPECT_EQ(kAuthenticationRequestInfo.value(),
|
|
msgs::Type::kAuthenticationRequest);
|
|
|
|
auto kUnknownInfo = MessageTypeDecoder::DecodeType({0xFF}, &used_bytes);
|
|
EXPECT_TRUE(kUnknownInfo.is_error());
|
|
}
|
|
|
|
} // namespace osp
|
|
} // namespace openscreen
|