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