1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 // Internal-only testing utilities. public/pw_rpc/test_method_context.h provides
16 // improved public-facing utilities for testing RPC services.
24 #include "pw_assert/light.h"
25 #include "pw_rpc/client.h"
26 #include "pw_rpc/internal/channel.h"
27 #include "pw_rpc/internal/method.h"
28 #include "pw_rpc/internal/packet.h"
29 #include "pw_rpc/internal/server.h"
33 template <size_t output_buffer_size>
34 class TestOutput : public ChannelOutput {
36 static constexpr size_t buffer_size() { return output_buffer_size; }
38 constexpr TestOutput(const char* name = "TestOutput")
39 : ChannelOutput(name), sent_data_{} {}
41 std::span<std::byte> AcquireBuffer() override { return buffer_; }
43 Status SendAndReleaseBuffer(std::span<const std::byte> buffer) override {
48 PW_ASSERT(buffer.data() == buffer_.data());
52 Result<internal::Packet> result = internal::Packet::FromBuffer(sent_data_);
53 EXPECT_EQ(OkStatus(), result.status());
54 sent_packet_ = result.value_or(internal::Packet());
58 std::span<const std::byte> buffer() const { return buffer_; }
60 size_t packet_count() const { return packet_count_; }
62 void set_send_status(Status status) { send_status_ = status; }
64 const std::span<const std::byte>& sent_data() const { return sent_data_; }
65 const internal::Packet& sent_packet() const {
66 EXPECT_GT(packet_count_, 0u);
71 std::array<std::byte, buffer_size()> buffer_;
72 std::span<const std::byte> sent_data_;
73 internal::Packet sent_packet_;
74 size_t packet_count_ = 0;
78 // Version of the internal::Server with extra methods exposed for testing.
79 class TestServer : public internal::Server {
81 using internal::Server::writers;
84 template <typename Service,
85 size_t output_buffer_size = 128,
86 uint32_t channel_id = 99,
87 uint32_t service_id = 16>
88 class ServerContextForTest {
90 static constexpr uint32_t kChannelId = channel_id;
91 static constexpr uint32_t kServiceId = service_id;
93 ServerContextForTest(const internal::Method& method)
94 : channel_(Channel::Create<kChannelId>(&output_)),
95 server_(std::span(&channel_, 1)),
97 context_(static_cast<internal::Server&>(server_),
98 static_cast<internal::Channel&>(channel_),
101 server_.RegisterService(service_);
104 // Creates a response packet for this context's channel, service, and method.
105 internal::Packet packet(std::span<const std::byte> payload) const {
106 return internal::Packet(internal::PacketType::RESPONSE,
109 context_.method().id(),
114 internal::ServerCall& get() { return context_; }
115 const auto& output() const { return output_; }
116 TestServer& server() { return static_cast<TestServer&>(server_); }
119 TestOutput<output_buffer_size> output_;
124 internal::ServerCall context_;
127 template <size_t output_buffer_size = 128,
128 size_t input_buffer_size = 128,
129 uint32_t channel_id = 99,
130 uint32_t service_id = 16,
131 uint32_t method_id = 111>
132 class ClientContextForTest {
134 static constexpr uint32_t kChannelId = channel_id;
135 static constexpr uint32_t kServiceId = service_id;
136 static constexpr uint32_t kMethodId = method_id;
138 ClientContextForTest()
139 : channel_(Channel::Create<kChannelId>(&output_)),
140 client_(std::span(&channel_, 1)) {}
142 const auto& output() const { return output_; }
143 Channel& channel() { return channel_; }
144 Client& client() { return client_; }
146 // Sends a packet to be processed by the client. Returns the client's
147 // ProcessPacket status.
148 Status SendPacket(internal::PacketType type,
149 Status status = OkStatus(),
150 std::span<const std::byte> payload = {}) {
151 internal::Packet packet(
152 type, kChannelId, kServiceId, kMethodId, payload, status);
153 std::byte buffer[input_buffer_size];
154 Result result = packet.Encode(buffer);
155 EXPECT_EQ(result.status(), OkStatus());
156 return client_.ProcessPacket(result.value_or(ConstByteSpan()));
159 Status SendResponse(Status status, std::span<const std::byte> payload) {
160 return SendPacket(internal::PacketType::RESPONSE, status, payload);
164 TestOutput<output_buffer_size> output_;
169 } // namespace pw::rpc