209 lines
8.1 KiB
C++
209 lines
8.1 KiB
C++
// Copyright 2021 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_rpc/internal/fake_channel_output.h"
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <memory>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_rpc/internal/channel.h"
|
|
#include "pw_rpc/internal/lock.h"
|
|
#include "pw_rpc/internal/packet.h"
|
|
|
|
namespace pw::rpc::internal::test {
|
|
namespace {
|
|
|
|
constexpr uint32_t kChannelId = 1;
|
|
constexpr uint32_t kServiceId = 1;
|
|
constexpr uint32_t kMethodId = 1;
|
|
constexpr uint32_t kCallId = 0;
|
|
constexpr std::array<std::byte, 3> kPayload = {
|
|
std::byte(1), std::byte(2), std::byte(3)};
|
|
|
|
class TestFakeChannelOutput final : public FakeChannelOutputBuffer<9, 128> {
|
|
public:
|
|
TestFakeChannelOutput() = default;
|
|
|
|
const ConstByteSpan& last_response(MethodType type) {
|
|
return payloads(type, kChannelId, kServiceId, kMethodId).back();
|
|
}
|
|
|
|
size_t total_payloads(MethodType type) {
|
|
return payloads(type, kChannelId, kServiceId, kMethodId).size();
|
|
}
|
|
};
|
|
|
|
TEST(FakeChannelOutput, SendAndClear) {
|
|
constexpr MethodType type = MethodType::kServerStreaming;
|
|
TestFakeChannelOutput output;
|
|
Channel channel(kChannelId, &output);
|
|
const internal::Packet server_stream_packet(PacketType::SERVER_STREAM,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
LockGuard lock(rpc_lock());
|
|
ASSERT_EQ(channel.Send(server_stream_packet), OkStatus());
|
|
ASSERT_EQ(output.last_response(type).size(), kPayload.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(
|
|
output.last_response(type).data(), kPayload.data(), kPayload.size()),
|
|
0);
|
|
EXPECT_EQ(output.total_payloads(type), 1u);
|
|
EXPECT_EQ(output.total_packets(), 1u);
|
|
EXPECT_FALSE(output.done());
|
|
|
|
output.clear();
|
|
EXPECT_EQ(output.total_payloads(type), 0u);
|
|
EXPECT_EQ(output.total_packets(), 0u);
|
|
EXPECT_FALSE(output.done());
|
|
}
|
|
|
|
TEST(FakeChannelOutput, SendAndFakeFutureResults) {
|
|
constexpr MethodType type = MethodType::kUnary;
|
|
TestFakeChannelOutput output;
|
|
Channel channel(kChannelId, &output);
|
|
const internal::Packet response_packet(PacketType::RESPONSE,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
LockGuard lock(rpc_lock());
|
|
EXPECT_EQ(channel.Send(response_packet), OkStatus());
|
|
EXPECT_EQ(output.total_payloads(type), 1u);
|
|
EXPECT_EQ(output.total_packets(), 1u);
|
|
EXPECT_TRUE(output.done());
|
|
|
|
// Multiple calls will return the same error status.
|
|
output.set_send_status(Status::Unknown());
|
|
EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
|
|
EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
|
|
EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
|
|
EXPECT_EQ(output.total_payloads(type), 1u);
|
|
EXPECT_EQ(output.total_packets(), 1u);
|
|
|
|
// Turn off error status behavior.
|
|
output.set_send_status(OkStatus());
|
|
EXPECT_EQ(channel.Send(response_packet), OkStatus());
|
|
EXPECT_EQ(output.total_payloads(type), 2u);
|
|
EXPECT_EQ(output.total_packets(), 2u);
|
|
|
|
const internal::Packet server_stream_packet(PacketType::SERVER_STREAM,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
EXPECT_EQ(channel.Send(server_stream_packet), OkStatus());
|
|
ASSERT_EQ(output.last_response(type).size(), kPayload.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(
|
|
output.last_response(type).data(), kPayload.data(), kPayload.size()),
|
|
0);
|
|
EXPECT_EQ(output.total_payloads(type), 2u);
|
|
EXPECT_EQ(output.total_packets(), 3u);
|
|
EXPECT_TRUE(output.done());
|
|
}
|
|
|
|
TEST(FakeChannelOutput, SendAndFakeSingleResult) {
|
|
constexpr MethodType type = MethodType::kUnary;
|
|
TestFakeChannelOutput output;
|
|
Channel channel(kChannelId, &output);
|
|
const internal::Packet response_packet(PacketType::RESPONSE,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
// Multiple calls will return the same error status.
|
|
const int packet_count_fail = 4;
|
|
output.set_send_status(Status::Unknown(), packet_count_fail);
|
|
LockGuard lock(rpc_lock());
|
|
|
|
for (int i = 0; i < packet_count_fail; ++i) {
|
|
EXPECT_EQ(channel.Send(response_packet), OkStatus());
|
|
}
|
|
EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
|
|
for (int i = 0; i < packet_count_fail; ++i) {
|
|
EXPECT_EQ(channel.Send(response_packet), OkStatus());
|
|
}
|
|
|
|
const size_t total_response_packets =
|
|
static_cast<size_t>(2 * packet_count_fail);
|
|
EXPECT_EQ(output.total_payloads(type), total_response_packets);
|
|
EXPECT_EQ(output.total_packets(), total_response_packets);
|
|
|
|
// Turn off error status behavior.
|
|
output.set_send_status(OkStatus());
|
|
EXPECT_EQ(channel.Send(response_packet), OkStatus());
|
|
EXPECT_EQ(output.total_payloads(type), total_response_packets + 1);
|
|
EXPECT_EQ(output.total_packets(), total_response_packets + 1);
|
|
}
|
|
|
|
TEST(FakeChannelOutput, SendResponseUpdated) {
|
|
TestFakeChannelOutput output;
|
|
Channel channel(kChannelId, &output);
|
|
const internal::Packet response_packet(PacketType::RESPONSE,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
LockGuard lock(rpc_lock());
|
|
ASSERT_EQ(channel.Send(response_packet), OkStatus());
|
|
ASSERT_EQ(output.last_response(MethodType::kUnary).size(), kPayload.size());
|
|
EXPECT_EQ(std::memcmp(output.last_response(MethodType::kUnary).data(),
|
|
kPayload.data(),
|
|
kPayload.size()),
|
|
0);
|
|
EXPECT_EQ(output.total_payloads(MethodType::kUnary), 1u);
|
|
EXPECT_EQ(output.total_packets(), 1u);
|
|
EXPECT_TRUE(output.done());
|
|
|
|
output.clear();
|
|
const internal::Packet packet_empty_payload(
|
|
PacketType::RESPONSE, kChannelId, kServiceId, kMethodId, kCallId, {});
|
|
EXPECT_EQ(channel.Send(packet_empty_payload), OkStatus());
|
|
EXPECT_EQ(output.last_response(MethodType::kUnary).size(), 0u);
|
|
EXPECT_EQ(output.total_payloads(MethodType::kUnary), 1u);
|
|
EXPECT_EQ(output.total_packets(), 1u);
|
|
EXPECT_TRUE(output.done());
|
|
|
|
const internal::Packet server_stream_packet(PacketType::SERVER_STREAM,
|
|
kChannelId,
|
|
kServiceId,
|
|
kMethodId,
|
|
kCallId,
|
|
kPayload);
|
|
ASSERT_EQ(channel.Send(server_stream_packet), OkStatus());
|
|
ASSERT_EQ(output.total_payloads(MethodType::kServerStreaming), 1u);
|
|
ASSERT_EQ(output.last_response(MethodType::kServerStreaming).size(),
|
|
kPayload.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(output.last_response(MethodType::kServerStreaming).data(),
|
|
kPayload.data(),
|
|
kPayload.size()),
|
|
0);
|
|
EXPECT_EQ(output.total_payloads(MethodType::kServerStreaming), 1u);
|
|
EXPECT_EQ(output.total_packets(), 2u);
|
|
EXPECT_TRUE(output.done());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::rpc::internal::test
|