You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.6 KiB
161 lines
4.6 KiB
// Copyright 2020 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_rpc/internal/packet.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_bytes/array.h"
|
|
#include "pw_protobuf/codegen.h"
|
|
#include "pw_protobuf/wire_format.h"
|
|
|
|
namespace pw::rpc::internal {
|
|
namespace {
|
|
|
|
using std::byte;
|
|
|
|
constexpr auto kPayload = bytes::Array<0x82, 0x02, 0xff, 0xff>();
|
|
|
|
constexpr auto kEncoded = bytes::Array<
|
|
// Payload
|
|
MakeKey(5, protobuf::WireType::kDelimited),
|
|
0x04,
|
|
0x82,
|
|
0x02,
|
|
0xff,
|
|
0xff,
|
|
|
|
// Packet type
|
|
MakeKey(1, protobuf::WireType::kVarint),
|
|
1, // RESPONSE
|
|
|
|
// Channel ID
|
|
MakeKey(2, protobuf::WireType::kVarint),
|
|
1,
|
|
|
|
// Service ID
|
|
MakeKey(3, protobuf::WireType::kFixed32),
|
|
42,
|
|
0,
|
|
0,
|
|
0,
|
|
|
|
// Method ID
|
|
MakeKey(4, protobuf::WireType::kFixed32),
|
|
100,
|
|
0,
|
|
0,
|
|
0,
|
|
|
|
// Status
|
|
MakeKey(6, protobuf::WireType::kVarint),
|
|
0x00>();
|
|
|
|
// Test that a default-constructed packet sets its members to the default
|
|
// protobuf values.
|
|
static_assert(Packet().type() == PacketType{});
|
|
static_assert(Packet().channel_id() == 0);
|
|
static_assert(Packet().service_id() == 0);
|
|
static_assert(Packet().method_id() == 0);
|
|
static_assert(Packet().status() == static_cast<Status::Code>(0));
|
|
static_assert(Packet().payload().empty());
|
|
|
|
TEST(Packet, Encode) {
|
|
byte buffer[64];
|
|
|
|
Packet packet(PacketType::RESPONSE, 1, 42, 100, kPayload);
|
|
|
|
auto result = packet.Encode(buffer);
|
|
ASSERT_EQ(OkStatus(), result.status());
|
|
ASSERT_EQ(kEncoded.size(), result.value().size());
|
|
EXPECT_EQ(std::memcmp(kEncoded.data(), buffer, kEncoded.size()), 0);
|
|
}
|
|
|
|
TEST(Packet, Encode_BufferTooSmall) {
|
|
byte buffer[2];
|
|
|
|
Packet packet(PacketType::RESPONSE, 1, 42, 100, kPayload);
|
|
|
|
auto result = packet.Encode(buffer);
|
|
EXPECT_EQ(Status::ResourceExhausted(), result.status());
|
|
}
|
|
|
|
TEST(Packet, Decode_ValidPacket) {
|
|
auto result = Packet::FromBuffer(kEncoded);
|
|
ASSERT_TRUE(result.ok());
|
|
|
|
auto& packet = result.value();
|
|
EXPECT_EQ(PacketType::RESPONSE, packet.type());
|
|
EXPECT_EQ(1u, packet.channel_id());
|
|
EXPECT_EQ(42u, packet.service_id());
|
|
EXPECT_EQ(100u, packet.method_id());
|
|
ASSERT_EQ(sizeof(kPayload), packet.payload().size());
|
|
EXPECT_EQ(
|
|
0,
|
|
std::memcmp(packet.payload().data(), kPayload.data(), kPayload.size()));
|
|
}
|
|
|
|
TEST(Packet, Decode_InvalidPacket) {
|
|
byte bad_data[] = {byte{0xFF}, byte{0x00}, byte{0x00}, byte{0xFF}};
|
|
EXPECT_EQ(Status::DataLoss(), Packet::FromBuffer(bad_data).status());
|
|
}
|
|
|
|
TEST(Packet, EncodeDecode) {
|
|
constexpr byte payload[]{byte(0x00), byte(0x01), byte(0x02), byte(0x03)};
|
|
|
|
Packet packet;
|
|
packet.set_channel_id(12);
|
|
packet.set_service_id(0xdeadbeef);
|
|
packet.set_method_id(0x03a82921);
|
|
packet.set_payload(payload);
|
|
packet.set_status(Status::Unavailable());
|
|
|
|
byte buffer[128];
|
|
Result result = packet.Encode(buffer);
|
|
ASSERT_EQ(result.status(), OkStatus());
|
|
|
|
std::span<byte> packet_data(buffer, result.value().size());
|
|
auto decode_result = Packet::FromBuffer(packet_data);
|
|
ASSERT_TRUE(decode_result.ok());
|
|
|
|
auto& decoded = decode_result.value();
|
|
EXPECT_EQ(decoded.type(), packet.type());
|
|
EXPECT_EQ(decoded.channel_id(), packet.channel_id());
|
|
EXPECT_EQ(decoded.service_id(), packet.service_id());
|
|
EXPECT_EQ(decoded.method_id(), packet.method_id());
|
|
ASSERT_EQ(decoded.payload().size(), packet.payload().size());
|
|
EXPECT_EQ(std::memcmp(decoded.payload().data(),
|
|
packet.payload().data(),
|
|
packet.payload().size()),
|
|
0);
|
|
EXPECT_EQ(decoded.status(), Status::Unavailable());
|
|
}
|
|
|
|
constexpr size_t kReservedSize = 2 /* type */ + 2 /* channel */ +
|
|
5 /* service */ + 5 /* method */ +
|
|
2 /* payload key */ + 2 /* status */;
|
|
|
|
TEST(Packet, PayloadUsableSpace_ExactFit) {
|
|
EXPECT_EQ(kReservedSize,
|
|
Packet(PacketType::RESPONSE, 1, 42, 100).MinEncodedSizeBytes());
|
|
}
|
|
|
|
TEST(Packet, PayloadUsableSpace_LargerVarints) {
|
|
EXPECT_EQ(
|
|
kReservedSize + 2 /* channel */, // service and method are Fixed32
|
|
Packet(PacketType::RESPONSE, 17000, 200, 200).MinEncodedSizeBytes());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::rpc::internal
|