1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/channel.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <cstddef>
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/packet.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/test_utils.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker namespace pw::rpc::internal {
24*61c4878aSAndroid Build Coastguard Worker namespace {
25*61c4878aSAndroid Build Coastguard Worker
TEST(ChannelOutput,Name)26*61c4878aSAndroid Build Coastguard Worker TEST(ChannelOutput, Name) {
27*61c4878aSAndroid Build Coastguard Worker class NameTester : public ChannelOutput {
28*61c4878aSAndroid Build Coastguard Worker public:
29*61c4878aSAndroid Build Coastguard Worker NameTester(const char* name) : ChannelOutput(name) {}
30*61c4878aSAndroid Build Coastguard Worker Status Send(span<const std::byte>) override { return OkStatus(); }
31*61c4878aSAndroid Build Coastguard Worker };
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker EXPECT_STREQ("hello_world", NameTester("hello_world").name());
34*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(nullptr, NameTester(nullptr).name());
35*61c4878aSAndroid Build Coastguard Worker }
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker constexpr Packet kTestPacket(
38*61c4878aSAndroid Build Coastguard Worker pwpb::PacketType::RESPONSE, 23, 42, 100, 0, {}, Status::NotFound());
39*61c4878aSAndroid Build Coastguard Worker const size_t kReservedSize = 2 /* type */ + 2 /* channel */ + 5 /* service */ +
40*61c4878aSAndroid Build Coastguard Worker 5 /* method */ + 2 /* payload key */ +
41*61c4878aSAndroid Build Coastguard Worker 2 /* status (if not OK) */;
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard Worker enum class ChannelId {
44*61c4878aSAndroid Build Coastguard Worker kOne = 1,
45*61c4878aSAndroid Build Coastguard Worker kTwo = 2,
46*61c4878aSAndroid Build Coastguard Worker };
47*61c4878aSAndroid Build Coastguard Worker
TEST(Channel,MaxSafePayload)48*61c4878aSAndroid Build Coastguard Worker TEST(Channel, MaxSafePayload) {
49*61c4878aSAndroid Build Coastguard Worker constexpr size_t kUint32Max = std::numeric_limits<uint32_t>::max();
50*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxPayloadSize = 64;
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker constexpr size_t kTestPayloadSize = MaxSafePayloadSize(kMaxPayloadSize);
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard Worker // Because it's impractical to test a payload that nears the limits of a
55*61c4878aSAndroid Build Coastguard Worker // uint32 varint, calculate the difference when using a smaller payload.
56*61c4878aSAndroid Build Coastguard Worker constexpr size_t kPayloadSizeTestLimitations =
57*61c4878aSAndroid Build Coastguard Worker varint::EncodedSize(kUint32Max) - varint::EncodedSize(kTestPayloadSize);
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard Worker // The buffer to use for encoding the RPC packet.
60*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kMaxPayloadSize - kPayloadSizeTestLimitations> buffer;
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kTestPayloadSize> payload;
63*61c4878aSAndroid Build Coastguard Worker for (size_t i = 0; i < payload.size(); i++) {
64*61c4878aSAndroid Build Coastguard Worker payload[i] = std::byte(i % std::numeric_limits<uint8_t>::max());
65*61c4878aSAndroid Build Coastguard Worker }
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker Packet packet(pwpb::PacketType::SERVER_STREAM,
68*61c4878aSAndroid Build Coastguard Worker /*channel_id=*/kUint32Max, // Varint, needs to be uint32_t max.
69*61c4878aSAndroid Build Coastguard Worker /*service_id=*/42, // Fixed-width. Value doesn't matter.
70*61c4878aSAndroid Build Coastguard Worker /*method_id=*/100, // Fixed-width. Value doesn't matter.
71*61c4878aSAndroid Build Coastguard Worker /*call_id=*/kUint32Max, // Varint, needs to be uint32_t max.
72*61c4878aSAndroid Build Coastguard Worker payload,
73*61c4878aSAndroid Build Coastguard Worker Status::Unauthenticated());
74*61c4878aSAndroid Build Coastguard Worker
75*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> result = packet.Encode(buffer);
76*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), result.status());
77*61c4878aSAndroid Build Coastguard Worker }
78*61c4878aSAndroid Build Coastguard Worker
TEST(Channel,MaxSafePayload_OffByOne)79*61c4878aSAndroid Build Coastguard Worker TEST(Channel, MaxSafePayload_OffByOne) {
80*61c4878aSAndroid Build Coastguard Worker constexpr size_t kUint32Max = std::numeric_limits<uint32_t>::max();
81*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxPayloadSize = 64;
82*61c4878aSAndroid Build Coastguard Worker
83*61c4878aSAndroid Build Coastguard Worker constexpr size_t kTestPayloadSize = MaxSafePayloadSize(kMaxPayloadSize);
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker // Because it's impractical to test a payload that nears the limits of a
86*61c4878aSAndroid Build Coastguard Worker // uint32 varint, calculate the difference when using a smaller payload.
87*61c4878aSAndroid Build Coastguard Worker constexpr size_t kPayloadSizeTestLimitations =
88*61c4878aSAndroid Build Coastguard Worker varint::EncodedSize(kUint32Max) - varint::EncodedSize(kTestPayloadSize);
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard Worker // The buffer to use for encoding the RPC packet.
91*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kMaxPayloadSize - kPayloadSizeTestLimitations - 1>
92*61c4878aSAndroid Build Coastguard Worker buffer;
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, kTestPayloadSize> payload;
95*61c4878aSAndroid Build Coastguard Worker for (size_t i = 0; i < payload.size(); i++) {
96*61c4878aSAndroid Build Coastguard Worker payload[i] = std::byte(i % std::numeric_limits<uint8_t>::max());
97*61c4878aSAndroid Build Coastguard Worker }
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker Packet packet(pwpb::PacketType::SERVER_STREAM,
100*61c4878aSAndroid Build Coastguard Worker /*channel_id=*/kUint32Max, // Varint, needs to be uint32_t max.
101*61c4878aSAndroid Build Coastguard Worker /*service_id=*/42, // Fixed-width. Value doesn't matter.
102*61c4878aSAndroid Build Coastguard Worker /*method_id=*/100, // Fixed-width. Value doesn't matter.
103*61c4878aSAndroid Build Coastguard Worker /*call_id=*/kUint32Max, // Varint, needs to be uint32_t max.
104*61c4878aSAndroid Build Coastguard Worker payload,
105*61c4878aSAndroid Build Coastguard Worker Status::Unauthenticated());
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> result = packet.Encode(buffer);
108*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(Status::ResourceExhausted(), result.status());
109*61c4878aSAndroid Build Coastguard Worker }
110*61c4878aSAndroid Build Coastguard Worker
TEST(Channel,Create_FromEnum)111*61c4878aSAndroid Build Coastguard Worker TEST(Channel, Create_FromEnum) {
112*61c4878aSAndroid Build Coastguard Worker constexpr rpc::Channel one = Channel::Create<ChannelId::kOne>(nullptr);
113*61c4878aSAndroid Build Coastguard Worker constexpr rpc::Channel two = Channel::Create<ChannelId::kTwo>(nullptr);
114*61c4878aSAndroid Build Coastguard Worker static_assert(one.id() == 1);
115*61c4878aSAndroid Build Coastguard Worker static_assert(two.id() == 2);
116*61c4878aSAndroid Build Coastguard Worker }
117*61c4878aSAndroid Build Coastguard Worker
TEST(Channel,TestPacket_ReservedSizeMatchesMinEncodedSizeBytes)118*61c4878aSAndroid Build Coastguard Worker TEST(Channel, TestPacket_ReservedSizeMatchesMinEncodedSizeBytes) {
119*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kReservedSize, kTestPacket.MinEncodedSizeBytes());
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker
TEST(ExtractChannelId,ValidPacket)122*61c4878aSAndroid Build Coastguard Worker TEST(ExtractChannelId, ValidPacket) {
123*61c4878aSAndroid Build Coastguard Worker std::byte buffer[64] = {};
124*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> result = kTestPacket.Encode(buffer);
125*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(result.status(), OkStatus());
126*61c4878aSAndroid Build Coastguard Worker
127*61c4878aSAndroid Build Coastguard Worker Result<uint32_t> channel_id = ExtractChannelId(*result);
128*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(channel_id.status(), OkStatus());
129*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(*channel_id, 23u);
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker
TEST(ExtractChannelId,InvalidPacket)132*61c4878aSAndroid Build Coastguard Worker TEST(ExtractChannelId, InvalidPacket) {
133*61c4878aSAndroid Build Coastguard Worker constexpr std::byte buffer[64] = {std::byte{1}, std::byte{2}};
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker Result<uint32_t> channel_id = ExtractChannelId(buffer);
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(channel_id.status(), Status::DataLoss());
138*61c4878aSAndroid Build Coastguard Worker }
139*61c4878aSAndroid Build Coastguard Worker
TEST(ExtractChannelId,ChangeChannelIdToValidValue)140*61c4878aSAndroid Build Coastguard Worker TEST(ExtractChannelId, ChangeChannelIdToValidValue) {
141*61c4878aSAndroid Build Coastguard Worker std::byte buffer[64] = {};
142*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> result = kTestPacket.Encode(buffer);
143*61c4878aSAndroid Build Coastguard Worker ByteSpan packet(buffer, result.value().size());
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 0), OkStatus());
146*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 0u);
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 1), OkStatus());
149*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 1u);
150*61c4878aSAndroid Build Coastguard Worker
151*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 23), OkStatus());
152*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 23u);
153*61c4878aSAndroid Build Coastguard Worker
154*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 127), OkStatus());
155*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 127u);
156*61c4878aSAndroid Build Coastguard Worker
157*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId<0>(packet), OkStatus());
158*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 0u);
159*61c4878aSAndroid Build Coastguard Worker
160*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId<1>(packet), OkStatus());
161*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 1u);
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId<23>(packet), OkStatus());
164*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 23u);
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId<127>(packet), OkStatus());
167*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ExtractChannelId(packet).value(), 127u);
168*61c4878aSAndroid Build Coastguard Worker }
169*61c4878aSAndroid Build Coastguard Worker
TEST(ExtractChannelId,ChangeChannelIdTooLarge)170*61c4878aSAndroid Build Coastguard Worker TEST(ExtractChannelId, ChangeChannelIdTooLarge) {
171*61c4878aSAndroid Build Coastguard Worker constexpr Packet kChannelIdTooLargePacket(
172*61c4878aSAndroid Build Coastguard Worker pwpb::PacketType::RESPONSE, 128, 42, 100, 0, {}, Status::NotFound());
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker std::byte buffer[64] = {};
175*61c4878aSAndroid Build Coastguard Worker Result<ConstByteSpan> result = kChannelIdTooLargePacket.Encode(buffer);
176*61c4878aSAndroid Build Coastguard Worker ByteSpan packet(buffer, result.value().size());
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 0), Status::OutOfRange());
179*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 1), Status::OutOfRange());
180*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 23), Status::OutOfRange());
181*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 127), Status::OutOfRange());
182*61c4878aSAndroid Build Coastguard Worker }
183*61c4878aSAndroid Build Coastguard Worker
TEST(ExtractChannelId,ChangeChannelIdNoChannelFound)184*61c4878aSAndroid Build Coastguard Worker TEST(ExtractChannelId, ChangeChannelIdNoChannelFound) {
185*61c4878aSAndroid Build Coastguard Worker std::byte packet[64] = {};
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 0), Status::DataLoss());
188*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 1), Status::DataLoss());
189*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 23), Status::DataLoss());
190*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ChangeEncodedChannelId(packet, 127), Status::DataLoss());
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker } // namespace
194*61c4878aSAndroid Build Coastguard Worker } // namespace pw::rpc::internal
195