• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
18 #include "pw_bytes/array.h"
19 #include "pw_protobuf/codegen.h"
20 #include "pw_protobuf/wire_format.h"
21 
22 namespace pw::rpc::internal {
23 namespace {
24 
25 using std::byte;
26 
27 constexpr auto kPayload = bytes::Array<0x82, 0x02, 0xff, 0xff>();
28 
29 constexpr auto kEncoded = bytes::Array<
30     // Payload
31     MakeKey(5, protobuf::WireType::kDelimited),
32     0x04,
33     0x82,
34     0x02,
35     0xff,
36     0xff,
37 
38     // Packet type
39     MakeKey(1, protobuf::WireType::kVarint),
40     1,  // RESPONSE
41 
42     // Channel ID
43     MakeKey(2, protobuf::WireType::kVarint),
44     1,
45 
46     // Service ID
47     MakeKey(3, protobuf::WireType::kFixed32),
48     42,
49     0,
50     0,
51     0,
52 
53     // Method ID
54     MakeKey(4, protobuf::WireType::kFixed32),
55     100,
56     0,
57     0,
58     0,
59 
60     // Status
61     MakeKey(6, protobuf::WireType::kVarint),
62     0x00>();
63 
64 // Test that a default-constructed packet sets its members to the default
65 // protobuf values.
66 static_assert(Packet().type() == PacketType{});
67 static_assert(Packet().channel_id() == 0);
68 static_assert(Packet().service_id() == 0);
69 static_assert(Packet().method_id() == 0);
70 static_assert(Packet().status() == static_cast<Status::Code>(0));
71 static_assert(Packet().payload().empty());
72 
TEST(Packet,Encode)73 TEST(Packet, Encode) {
74   byte buffer[64];
75 
76   Packet packet(PacketType::RESPONSE, 1, 42, 100, kPayload);
77 
78   auto result = packet.Encode(buffer);
79   ASSERT_EQ(OkStatus(), result.status());
80   ASSERT_EQ(kEncoded.size(), result.value().size());
81   EXPECT_EQ(std::memcmp(kEncoded.data(), buffer, kEncoded.size()), 0);
82 }
83 
TEST(Packet,Encode_BufferTooSmall)84 TEST(Packet, Encode_BufferTooSmall) {
85   byte buffer[2];
86 
87   Packet packet(PacketType::RESPONSE, 1, 42, 100, kPayload);
88 
89   auto result = packet.Encode(buffer);
90   EXPECT_EQ(Status::ResourceExhausted(), result.status());
91 }
92 
TEST(Packet,Decode_ValidPacket)93 TEST(Packet, Decode_ValidPacket) {
94   auto result = Packet::FromBuffer(kEncoded);
95   ASSERT_TRUE(result.ok());
96 
97   auto& packet = result.value();
98   EXPECT_EQ(PacketType::RESPONSE, packet.type());
99   EXPECT_EQ(1u, packet.channel_id());
100   EXPECT_EQ(42u, packet.service_id());
101   EXPECT_EQ(100u, packet.method_id());
102   ASSERT_EQ(sizeof(kPayload), packet.payload().size());
103   EXPECT_EQ(
104       0,
105       std::memcmp(packet.payload().data(), kPayload.data(), kPayload.size()));
106 }
107 
TEST(Packet,Decode_InvalidPacket)108 TEST(Packet, Decode_InvalidPacket) {
109   byte bad_data[] = {byte{0xFF}, byte{0x00}, byte{0x00}, byte{0xFF}};
110   EXPECT_EQ(Status::DataLoss(), Packet::FromBuffer(bad_data).status());
111 }
112 
TEST(Packet,EncodeDecode)113 TEST(Packet, EncodeDecode) {
114   constexpr byte payload[]{byte(0x00), byte(0x01), byte(0x02), byte(0x03)};
115 
116   Packet packet;
117   packet.set_channel_id(12);
118   packet.set_service_id(0xdeadbeef);
119   packet.set_method_id(0x03a82921);
120   packet.set_payload(payload);
121   packet.set_status(Status::Unavailable());
122 
123   byte buffer[128];
124   Result result = packet.Encode(buffer);
125   ASSERT_EQ(result.status(), OkStatus());
126 
127   std::span<byte> packet_data(buffer, result.value().size());
128   auto decode_result = Packet::FromBuffer(packet_data);
129   ASSERT_TRUE(decode_result.ok());
130 
131   auto& decoded = decode_result.value();
132   EXPECT_EQ(decoded.type(), packet.type());
133   EXPECT_EQ(decoded.channel_id(), packet.channel_id());
134   EXPECT_EQ(decoded.service_id(), packet.service_id());
135   EXPECT_EQ(decoded.method_id(), packet.method_id());
136   ASSERT_EQ(decoded.payload().size(), packet.payload().size());
137   EXPECT_EQ(std::memcmp(decoded.payload().data(),
138                         packet.payload().data(),
139                         packet.payload().size()),
140             0);
141   EXPECT_EQ(decoded.status(), Status::Unavailable());
142 }
143 
144 constexpr size_t kReservedSize = 2 /* type */ + 2 /* channel */ +
145                                  5 /* service */ + 5 /* method */ +
146                                  2 /* payload key */ + 2 /* status */;
147 
TEST(Packet,PayloadUsableSpace_ExactFit)148 TEST(Packet, PayloadUsableSpace_ExactFit) {
149   EXPECT_EQ(kReservedSize,
150             Packet(PacketType::RESPONSE, 1, 42, 100).MinEncodedSizeBytes());
151 }
152 
TEST(Packet,PayloadUsableSpace_LargerVarints)153 TEST(Packet, PayloadUsableSpace_LargerVarints) {
154   EXPECT_EQ(
155       kReservedSize + 2 /* channel */,  // service and method are Fixed32
156       Packet(PacketType::RESPONSE, 17000, 200, 200).MinEncodedSizeBytes());
157 }
158 
159 }  // namespace
160 }  // namespace pw::rpc::internal
161