1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_rpc_transport/simple_framing.h"
16
17 #include <algorithm>
18 #include <array>
19 #include <random>
20
21 #include "pw_bytes/span.h"
22 #include "pw_log/log.h"
23 #include "pw_status/status.h"
24 #include "pw_unit_test/framework.h"
25
26 namespace pw::rpc {
27 namespace {
28
29 constexpr size_t kMaxPacketSize = 256;
30
31 struct TestParams {
32 size_t packet_size = 0;
33 size_t max_frame_size = 0;
34 };
35
36 constexpr std::array<TestParams, 8> kTestCases = {
37 // Packet fits in one frame.
38 TestParams{.packet_size = 5, .max_frame_size = 100},
39 // Typical parameters for RPC packet and mailbox frame size.
40 TestParams{.packet_size = 100, .max_frame_size = 128},
41 // Smallest packet.
42 TestParams{.packet_size = 1, .max_frame_size = 16},
43 // Small packet, small frame.
44 TestParams{.packet_size = 16, .max_frame_size = 5},
45 // Odd-sized packet, small frame.
46 TestParams{.packet_size = 77, .max_frame_size = 16},
47 // Frame size and packet size off by one.
48 TestParams{.packet_size = 11, .max_frame_size = 10},
49 // Almost at the limit.
50 TestParams{.packet_size = kMaxPacketSize - 1,
51 .max_frame_size = kMaxPacketSize - 2},
52 // At the limit.
53 TestParams{.packet_size = kMaxPacketSize,
54 .max_frame_size = kMaxPacketSize}};
55
MakePacket(ByteSpan dst_buffer)56 void MakePacket(ByteSpan dst_buffer) {
57 static uint32_t rg_seed = 0x123;
58 unsigned char c = 0;
59 for (auto& i : dst_buffer) {
60 i = std::byte{c++};
61 }
62 std::mt19937 rg(rg_seed++);
63 std::shuffle(dst_buffer.begin(), dst_buffer.end(), rg);
64 }
65
CopyFrame(RpcFrame frame,std::vector<std::byte> & dst)66 void CopyFrame(RpcFrame frame, std::vector<std::byte>& dst) {
67 std::copy(frame.header.begin(), frame.header.end(), std::back_inserter(dst));
68 std::copy(
69 frame.payload.begin(), frame.payload.end(), std::back_inserter(dst));
70 }
71
TEST(SimpleRpcFrameEncodeDecodeTest,EncodeThenDecode)72 TEST(SimpleRpcFrameEncodeDecodeTest, EncodeThenDecode) {
73 for (auto test_case : kTestCases) {
74 const size_t packet_size = test_case.packet_size;
75 const size_t max_frame_size = test_case.max_frame_size;
76 PW_LOG_INFO("EncodeThenDecode: packet_size = %d, max_frame_size = %d",
77 static_cast<int>(packet_size),
78 static_cast<int>(max_frame_size));
79
80 std::vector<std::byte> src(packet_size);
81 MakePacket(src);
82
83 std::vector<std::byte> encoded;
84 std::vector<std::byte> decoded;
85
86 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
87
88 ASSERT_EQ(encoder.Encode(src,
89 max_frame_size,
90 [&encoded](RpcFrame& frame) {
91 CopyFrame(frame, encoded);
92 return OkStatus();
93 }),
94 OkStatus());
95
96 SimpleRpcPacketDecoder<kMaxPacketSize> decoder;
97
98 ASSERT_EQ(decoder.Decode(encoded,
99 [&decoded](ConstByteSpan packet) {
100 std::copy(packet.begin(),
101 packet.end(),
102 std::back_inserter(decoded));
103 }),
104 OkStatus());
105
106 EXPECT_TRUE(std::equal(src.begin(), src.end(), decoded.begin()));
107 }
108 }
109
TEST(SimpleRpcFrameEncodeDecodeTest,OneByteAtTimeDecoding)110 TEST(SimpleRpcFrameEncodeDecodeTest, OneByteAtTimeDecoding) {
111 for (auto test_case : kTestCases) {
112 const size_t packet_size = test_case.packet_size;
113 const size_t max_frame_size = test_case.max_frame_size;
114 PW_LOG_INFO("EncodeThenDecode: packet_size = %d, max_frame_size = %d",
115 static_cast<int>(packet_size),
116 static_cast<int>(max_frame_size));
117
118 std::vector<std::byte> src(packet_size);
119 MakePacket(src);
120
121 std::vector<std::byte> encoded;
122 std::vector<std::byte> decoded;
123
124 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
125
126 ASSERT_EQ(encoder.Encode(src,
127 max_frame_size,
128 [&encoded](RpcFrame& frame) {
129 CopyFrame(frame, encoded);
130 return OkStatus();
131 }),
132 OkStatus());
133
134 SimpleRpcPacketDecoder<kMaxPacketSize> decoder;
135
136 for (std::byte b : encoded) {
137 auto buffer_span = span(&b, 1);
138 ASSERT_EQ(decoder.Decode(buffer_span,
139 [&decoded](ConstByteSpan packet) {
140 std::copy(packet.begin(),
141 packet.end(),
142 std::back_inserter(decoded));
143 }),
144 OkStatus());
145 }
146
147 EXPECT_TRUE(std::equal(src.begin(), src.end(), decoded.begin()));
148 }
149 }
150
TEST(SimpleRpcFrameTest,MissingFirstFrame)151 TEST(SimpleRpcFrameTest, MissingFirstFrame) {
152 // Sends two packets, the first packet is missing its first frame. The decoder
153 // ignores the remaining frames of the first packet but still picks up the
154 // second packet.
155 constexpr size_t kPacketSize = 77;
156 constexpr size_t kMaxFrameSize = 16;
157
158 std::vector<std::byte> src1(kPacketSize);
159 MakePacket(src1);
160
161 std::vector<std::byte> src2(kPacketSize);
162 MakePacket(src2);
163
164 std::vector<std::byte> decoded;
165
166 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
167 struct EncodeState {
168 size_t frame_counter = 0;
169 std::vector<std::byte> encoded;
170 } state;
171
172 ASSERT_EQ(encoder.Encode(src1,
173 kMaxFrameSize,
174 [&state](RpcFrame& frame) {
175 state.frame_counter++;
176 if (state.frame_counter > 1) {
177 // Skip the first frame.
178 CopyFrame(frame, state.encoded);
179 }
180 return OkStatus();
181 }),
182 OkStatus());
183
184 ASSERT_EQ(encoder.Encode(src2,
185 kMaxFrameSize,
186 [&state](RpcFrame& frame) {
187 CopyFrame(frame, state.encoded);
188 return OkStatus();
189 }),
190 OkStatus());
191
192 SimpleRpcPacketDecoder<kMaxPacketSize> decoder;
193
194 ASSERT_EQ(decoder.Decode(state.encoded,
195 [&decoded](ConstByteSpan packet) {
196 std::copy(packet.begin(),
197 packet.end(),
198 std::back_inserter(decoded));
199 }),
200 OkStatus());
201
202 EXPECT_TRUE(std::equal(src2.begin(), src2.end(), decoded.begin()));
203 }
204
TEST(SimpleRpcFrameTest,MissingInternalFrame)205 TEST(SimpleRpcFrameTest, MissingInternalFrame) {
206 // Sends two packets, the first packet is missing its second frame. The
207 // decoder ignores the remaining frames of the first packet and the second
208 // packet as well but eventually stumbles upon the frame header in the third
209 // packet and processes that packet.
210 constexpr size_t kPacketSize = 77;
211 constexpr size_t kMaxFrameSize = 16;
212
213 std::vector<std::byte> src1(kPacketSize);
214 MakePacket(src1);
215
216 std::vector<std::byte> src2(kPacketSize);
217 MakePacket(src2);
218
219 std::vector<std::byte> src3(kPacketSize);
220 MakePacket(src3);
221
222 std::vector<std::byte> decoded;
223
224 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
225 struct EncodeState {
226 size_t frame_counter = 0;
227 std::vector<std::byte> encoded;
228 } encode_state;
229
230 ASSERT_EQ(encoder.Encode(src1,
231 kMaxFrameSize,
232 [&encode_state](RpcFrame& frame) {
233 encode_state.frame_counter++;
234 if (encode_state.frame_counter != 2) {
235 // Skip the second frame.
236 CopyFrame(frame, encode_state.encoded);
237 }
238 return OkStatus();
239 }),
240 OkStatus());
241
242 ASSERT_EQ(encoder.Encode(src2,
243 kMaxFrameSize,
244 [&encode_state](RpcFrame& frame) {
245 CopyFrame(frame, encode_state.encoded);
246 return OkStatus();
247 }),
248 OkStatus());
249
250 ASSERT_EQ(encoder.Encode(src3,
251 kMaxFrameSize,
252 [&encode_state](RpcFrame& frame) {
253 CopyFrame(frame, encode_state.encoded);
254 return OkStatus();
255 }),
256 OkStatus());
257
258 SimpleRpcPacketDecoder<kMaxPacketSize> decoder;
259
260 // First packet is decoded but it doesn't have correct bytes, as one of its
261 // frames has never been received. Second packet is not received because its
262 // header has been consumed by the first packet. By that point the decoder
263 // knows that something is wrong and tries to recover as soon as it receives
264 // bytes that look as the valid header. So we eventually receive the third
265 // packet and it is correct.
266 struct DecodeState {
267 std::vector<std::byte> decoded1;
268 std::vector<std::byte> decoded2;
269 size_t packet_counter = 0;
270 } decode_state;
271
272 ASSERT_EQ(
273 decoder.Decode(encode_state.encoded,
274 [&decode_state](ConstByteSpan packet) {
275 decode_state.packet_counter++;
276 if (decode_state.packet_counter == 1) {
277 std::copy(packet.begin(),
278 packet.end(),
279 std::back_inserter(decode_state.decoded1));
280 }
281 if (decode_state.packet_counter == 2) {
282 std::copy(packet.begin(),
283 packet.end(),
284 std::back_inserter(decode_state.decoded2));
285 }
286 }),
287 OkStatus());
288
289 EXPECT_EQ(decode_state.packet_counter, 2ul);
290
291 EXPECT_EQ(decode_state.decoded1.size(), src1.size());
292 EXPECT_FALSE(
293 std::equal(src1.begin(), src1.end(), decode_state.decoded1.begin()));
294
295 EXPECT_TRUE(
296 std::equal(src3.begin(), src3.end(), decode_state.decoded2.begin()));
297 }
298
TEST(SimpleRpcPacketEncoder,PacketTooBig)299 TEST(SimpleRpcPacketEncoder, PacketTooBig) {
300 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
301 constexpr size_t kMaxFrameSize = 100;
302 std::array<std::byte, kMaxPacketSize + 1> src{};
303
304 EXPECT_EQ(
305 encoder.Encode(src, kMaxFrameSize, [](RpcFrame&) { return OkStatus(); }),
306 Status::FailedPrecondition());
307 }
308
TEST(SimpleRpcPacketEncoder,MaxFrameSizeTooSmall)309 TEST(SimpleRpcPacketEncoder, MaxFrameSizeTooSmall) {
310 SimpleRpcPacketEncoder<kMaxPacketSize> encoder;
311 std::array<std::byte, kMaxPacketSize> src{};
312
313 EXPECT_EQ(encoder.Encode(
314 src, encoder.kHeaderSize, [](RpcFrame&) { return OkStatus(); }),
315 Status::FailedPrecondition());
316
317 EXPECT_EQ(
318 encoder.Encode(
319 src, encoder.kHeaderSize + 1, [](RpcFrame&) { return OkStatus(); }),
320 OkStatus());
321 }
322
TEST(SimpleRpcFrameTest,EncoderBufferLargerThanDecoderBuffer)323 TEST(SimpleRpcFrameTest, EncoderBufferLargerThanDecoderBuffer) {
324 constexpr size_t kLargePacketSize = 150;
325 constexpr size_t kSmallPacketSize = 120;
326 constexpr size_t kMaxFrameSize = 16;
327
328 // Decoder isn't able to receive the whole packet because it needs to be
329 // buffered but the internal buffer is too small; the packet is thus
330 // discarded. The second packet is received without issues as it's small
331 // enough to fit in the decoder buffer.
332 constexpr size_t kEncoderMaxPacketSize = 256;
333 constexpr size_t kDecoderMaxPacketSize = 128;
334
335 std::vector<std::byte> src1(kLargePacketSize);
336 MakePacket(src1);
337
338 std::vector<std::byte> src2(kSmallPacketSize);
339 MakePacket(src1);
340
341 std::vector<std::byte> encoded;
342 std::vector<std::byte> decoded;
343
344 SimpleRpcPacketEncoder<kEncoderMaxPacketSize> encoder;
345
346 ASSERT_EQ(encoder.Encode(src1,
347 kMaxFrameSize,
348 [&encoded](RpcFrame& frame) {
349 CopyFrame(frame, encoded);
350 return OkStatus();
351 }),
352 OkStatus());
353
354 ASSERT_EQ(encoder.Encode(src2,
355 kMaxFrameSize,
356 [&encoded](RpcFrame& frame) {
357 CopyFrame(frame, encoded);
358 return OkStatus();
359 }),
360 OkStatus());
361
362 SimpleRpcPacketDecoder<kDecoderMaxPacketSize> decoder;
363
364 // We have to decode piecemeal here because otherwise the decoder can just
365 // pluck the packet from `encoded` without internally buffering it.
366 for (std::byte b : encoded) {
367 auto buffer_span = span(&b, 1);
368 ASSERT_EQ(decoder.Decode(buffer_span,
369 [&decoded](ConstByteSpan packet) {
370 std::copy(packet.begin(),
371 packet.end(),
372 std::back_inserter(decoded));
373 }),
374 OkStatus());
375 }
376
377 EXPECT_TRUE(std::equal(src2.begin(), src2.end(), decoded.begin()));
378 }
379
380 } // namespace
381 } // namespace pw::rpc
382