1 // Copyright 2021 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 #pragma once 15 16 #include <cstddef> 17 #include <cstdint> 18 #include <optional> 19 20 #include "pw_bytes/span.h" 21 #include "pw_rpc/client.h" 22 #include "pw_rpc/internal/method_info.h" 23 #include "pw_rpc/nanopb/fake_channel_output.h" 24 #include "pw_rpc/raw/client_testing.h" 25 26 namespace pw::rpc { 27 28 // TODO: b/234878467 - Document the client testing APIs. 29 30 // Sends packets to an RPC client as if it were a pw_rpc server. Accepts 31 // payloads as Nanopb structs. 32 class NanopbFakeServer : public FakeServer { 33 private: 34 template <auto kMethod> 35 using Response = typename internal::MethodInfo<kMethod>::Response; 36 37 public: 38 using FakeServer::FakeServer; 39 40 // Sends a response packet for a server or bidirectional streaming RPC to the 41 // client. 42 template <auto kMethod> 43 void SendResponse(Status status, 44 std::optional<uint32_t> call_id = std::nullopt) const { 45 FakeServer::SendResponse<kMethod>(status, call_id); 46 } 47 48 // Sends a response packet for a unary or client streaming streaming RPC to 49 // the client. 50 template <auto kMethod, 51 size_t kEncodeBufferSizeBytes = 2 * sizeof(Response<kMethod>)> 52 void SendResponse(const Response<kMethod>& payload, 53 Status status, 54 std::optional<uint32_t> call_id = std::nullopt) const { 55 std::byte buffer[kEncodeBufferSizeBytes] = {}; 56 FakeServer::SendResponse<kMethod>( 57 EncodeResponse<kMethod>(&payload, buffer), status, call_id); 58 } 59 60 // Sends a stream packet for a server or bidirectional streaming RPC to the 61 // client. 62 template <auto kMethod, 63 size_t kEncodeBufferSizeBytes = 2 * sizeof(Response<kMethod>)> 64 void SendServerStream(const Response<kMethod>& payload, 65 std::optional<uint32_t> call_id = std::nullopt) const { 66 std::byte buffer[kEncodeBufferSizeBytes] = {}; 67 FakeServer::SendServerStream<kMethod>( 68 EncodeResponse<kMethod>(&payload, buffer), call_id); 69 } 70 71 private: 72 template <auto kMethod> EncodeResponse(const void * payload,ByteSpan buffer)73 static ConstByteSpan EncodeResponse(const void* payload, ByteSpan buffer) { 74 const StatusWithSize result = 75 internal::MethodInfo<kMethod>::serde().response().Encode(payload, 76 buffer); 77 PW_ASSERT(result.ok()); 78 return span(buffer).first(result.size()); 79 } 80 }; 81 82 // Instantiates a NanopbFakeServer, Client, Channel, and NanopbFakeChannelOutput 83 // for testing RPC client calls. These components may be used individually, but 84 // are instantiated together for convenience. 85 template <size_t kMaxPackets = 10, 86 size_t kPacketEncodeBufferSizeBytes = 128, 87 size_t kPayloadsBufferSizeBytes = 256> 88 class NanopbClientTestContext { 89 public: NanopbClientTestContext()90 constexpr NanopbClientTestContext() 91 : channel_(Channel::Create<kDefaultChannelId>(&channel_output_)), 92 client_(span(&channel_, 1)), 93 packet_buffer_{}, 94 fake_server_( 95 channel_output_, client_, kDefaultChannelId, packet_buffer_) {} 96 channel()97 const Channel& channel() const { return channel_; } channel()98 Channel& channel() { return channel_; } 99 server()100 const NanopbFakeServer& server() const { return fake_server_; } server()101 NanopbFakeServer& server() { return fake_server_; } 102 client()103 const Client& client() const { return client_; } client()104 Client& client() { return client_; } 105 output()106 const auto& output() const { return channel_output_; } output()107 auto& output() { return channel_output_; } 108 109 private: 110 static constexpr uint32_t kDefaultChannelId = 1; 111 112 NanopbFakeChannelOutput<kMaxPackets, kPayloadsBufferSizeBytes> 113 channel_output_; 114 Channel channel_; 115 Client client_; 116 std::byte packet_buffer_[kPacketEncodeBufferSizeBytes]; 117 NanopbFakeServer fake_server_; 118 }; 119 120 } // namespace pw::rpc 121