xref: /aosp_15_r20/external/pigweed/pw_rpc/packet_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 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/internal/packet.h"
16 
17 #include "pw_bytes/array.h"
18 #include "pw_fuzzer/fuzztest.h"
19 #include "pw_protobuf/wire_format.h"
20 #include "pw_unit_test/framework.h"
21 
22 namespace pw::rpc::internal {
23 namespace {
24 
25 using protobuf::FieldKey;
26 using ::pw::rpc::internal::pwpb::PacketType;
27 using std::byte;
28 using namespace fuzzer;
29 
30 constexpr auto kPayload = bytes::Array<0x82, 0x02, 0xff, 0xff>();
31 
32 constexpr auto kEncoded = bytes::Array<
33     // Payload
34     uint32_t(FieldKey(5, protobuf::WireType::kDelimited)),
35     0x04,
36     0x82,
37     0x02,
38     0xff,
39     0xff,
40 
41     // Packet type
42     uint32_t(FieldKey(1, protobuf::WireType::kVarint)),
43     1,  // RESPONSE
44 
45     // Channel ID
46     uint32_t(FieldKey(2, protobuf::WireType::kVarint)),
47     1,
48 
49     // Service ID
50     uint32_t(FieldKey(3, protobuf::WireType::kFixed32)),
51     42,
52     0,
53     0,
54     0,
55 
56     // Method ID
57     uint32_t(FieldKey(4, protobuf::WireType::kFixed32)),
58     100,
59     0,
60     0,
61     0,
62 
63     // Status (not encoded if it is zero)
64     // FieldKey(6, protobuf::WireType::kVarint),
65     // 0x00
66 
67     // Call ID
68     uint32_t(FieldKey(7, protobuf::WireType::kVarint)),
69     7>();
70 
71 // Test that a default-constructed packet sets its members to the default
72 // protobuf values.
73 static_assert(Packet().type() == PacketType{});
74 static_assert(Packet().channel_id() == 0);
75 static_assert(Packet().service_id() == 0);
76 static_assert(Packet().method_id() == 0);
77 static_assert(Packet().status() == static_cast<Status::Code>(0));
78 static_assert(Packet().payload().empty());
79 
TEST(Packet,Encode)80 TEST(Packet, Encode) {
81   byte buffer[64];
82 
83   Packet packet(PacketType::RESPONSE, 1, 42, 100, 7, kPayload);
84 
85   auto result = packet.Encode(buffer);
86   ASSERT_EQ(OkStatus(), result.status());
87   ASSERT_EQ(kEncoded.size(), result.value().size());
88   EXPECT_EQ(std::memcmp(kEncoded.data(), buffer, kEncoded.size()), 0);
89 }
90 
TEST(Packet,Encode_BufferTooSmall)91 TEST(Packet, Encode_BufferTooSmall) {
92   byte buffer[2];
93 
94   Packet packet(PacketType::RESPONSE, 1, 42, 100, 12, kPayload);
95 
96   auto result = packet.Encode(buffer);
97   EXPECT_EQ(Status::ResourceExhausted(), result.status());
98 }
99 
TEST(Packet,Decode_ValidPacket)100 TEST(Packet, Decode_ValidPacket) {
101   auto result = Packet::FromBuffer(kEncoded);
102   ASSERT_TRUE(result.ok());
103 
104   auto& packet = result.value();
105   EXPECT_EQ(PacketType::RESPONSE, packet.type());
106   EXPECT_EQ(1u, packet.channel_id());
107   EXPECT_EQ(42u, packet.service_id());
108   EXPECT_EQ(100u, packet.method_id());
109   EXPECT_EQ(7u, packet.call_id());
110   ASSERT_EQ(sizeof(kPayload), packet.payload().size());
111   EXPECT_EQ(
112       0,
113       std::memcmp(packet.payload().data(), kPayload.data(), kPayload.size()));
114 }
115 
TEST(Packet,Decode_InvalidPacket)116 TEST(Packet, Decode_InvalidPacket) {
117   byte bad_data[] = {byte{0xFF}, byte{0x00}, byte{0x00}, byte{0xFF}};
118   EXPECT_EQ(Status::DataLoss(), Packet::FromBuffer(bad_data).status());
119 }
120 
EncodeDecode(uint32_t channel_id,uint32_t service_id,uint32_t method_id,uint32_t call_id,ConstByteSpan payload,Status status)121 void EncodeDecode(uint32_t channel_id,
122                   uint32_t service_id,
123                   uint32_t method_id,
124                   uint32_t call_id,
125                   ConstByteSpan payload,
126                   Status status) {
127   Packet packet;
128   packet.set_channel_id(channel_id);
129   packet.set_service_id(service_id);
130   packet.set_method_id(method_id);
131   packet.set_call_id(call_id);
132   packet.set_payload(payload);
133   packet.set_status(status);
134 
135   byte buffer[128];
136   Result result = packet.Encode(buffer);
137   ASSERT_EQ(result.status(), OkStatus());
138 
139   span<byte> packet_data(buffer, result.value().size());
140   auto decode_result = Packet::FromBuffer(packet_data);
141   ASSERT_TRUE(decode_result.ok());
142 
143   auto& decoded = decode_result.value();
144   EXPECT_EQ(decoded.type(), packet.type());
145   EXPECT_EQ(decoded.channel_id(), packet.channel_id());
146   EXPECT_EQ(decoded.service_id(), packet.service_id());
147   EXPECT_EQ(decoded.method_id(), packet.method_id());
148   EXPECT_EQ(decoded.call_id(), packet.call_id());
149   ASSERT_EQ(decoded.payload().size(), packet.payload().size());
150   EXPECT_EQ(std::memcmp(decoded.payload().data(),
151                         packet.payload().data(),
152                         packet.payload().size()),
153             0);
154   EXPECT_EQ(decoded.status(), status);
155 }
156 
TEST(Packet,EncodeDecodeFixed)157 TEST(Packet, EncodeDecodeFixed) {
158   constexpr byte payload[]{byte(0x00), byte(0x01), byte(0x02), byte(0x03)};
159   EncodeDecode(12, 0xdeadbeef, 0x03a82921, 33, payload, Status::Unavailable());
160 }
161 
162 FUZZ_TEST(Packet, EncodeDecode)
163     .WithDomains(NonZero<uint32_t>(),
164                  NonZero<uint32_t>(),
165                  NonZero<uint32_t>(),
166                  NonZero<uint32_t>(),
167                  VectorOf<100>(Arbitrary<byte>()),
168                  Arbitrary<Status>());
169 
170 constexpr size_t kReservedSize = 2 /* type */ + 2 /* channel */ +
171                                  5 /* service */ + 5 /* method */ +
172                                  2 /* payload key */ + 2 /* status */;
173 
TEST(Packet,PayloadUsableSpace_ExactFit)174 TEST(Packet, PayloadUsableSpace_ExactFit) {
175   EXPECT_EQ(
176       kReservedSize,
177       Packet(PacketType::RESPONSE, 1, 42, 100, 28282).MinEncodedSizeBytes());
178 }
179 
TEST(Packet,PayloadUsableSpace_LargerVarints)180 TEST(Packet, PayloadUsableSpace_LargerVarints) {
181   EXPECT_EQ(kReservedSize + 2 /* channel */,  // service and method are Fixed32
182             Packet(PacketType::RESPONSE, 17000, 200, 200, 28282)
183                 .MinEncodedSizeBytes());
184 }
185 
186 }  // namespace
187 }  // namespace pw::rpc::internal
188