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 <type_traits> 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/internal/packet.h" 24 #include "pw_rpc/method_type.h" 25 #include "pw_rpc/raw/fake_channel_output.h" 26 27 namespace pw::rpc { 28 29 // TODO(pwbug/477): Document the client testing APIs. 30 31 // Sends packets to an RPC client as if it were a pw_rpc server. 32 class FakeServer { 33 public: FakeServer(internal::test::FakeChannelOutput & output,Client & client,uint32_t channel_id,ByteSpan packet_buffer)34 constexpr FakeServer(internal::test::FakeChannelOutput& output, 35 Client& client, 36 uint32_t channel_id, 37 ByteSpan packet_buffer) 38 : output_(output), 39 client_(client), 40 channel_id_(channel_id), 41 packet_buffer_(packet_buffer) {} 42 43 // Sends a response packet for a server or bidirectional streaming RPC to the 44 // client. 45 template <auto kMethod, 46 typename = std::enable_if_t< 47 HasServerStream(internal::MethodInfo<kMethod>::kType)>> SendResponse(Status status)48 void SendResponse(Status status) const { 49 SendPacket<kMethod>(internal::PacketType::RESPONSE, {}, status); 50 } 51 52 // Sends a response packet for a unary or client streaming streaming RPC to 53 // the client. 54 template <auto kMethod, 55 typename = std::enable_if_t< 56 !HasServerStream(internal::MethodInfo<kMethod>::kType)>> SendResponse(ConstByteSpan payload,Status status)57 void SendResponse(ConstByteSpan payload, Status status) const { 58 SendPacket<kMethod>(internal::PacketType::RESPONSE, payload, status); 59 } 60 61 // Sends a stream packet for a server or bidirectional streaming RPC to the 62 // client. 63 template <auto kMethod> SendServerStream(ConstByteSpan payload)64 void SendServerStream(ConstByteSpan payload) const { 65 static_assert(HasServerStream(internal::MethodInfo<kMethod>::kType), 66 "Only server and bidirectional streaming methods can receive " 67 "server stream packets"); 68 SendPacket<kMethod>(internal::PacketType::SERVER_STREAM, payload); 69 } 70 71 // Sends a server error packet to the client. 72 template <auto kMethod> SendServerError(Status error)73 void SendServerError(Status error) const { 74 SendPacket<kMethod>(internal::PacketType::SERVER_ERROR, {}, error); 75 } 76 77 private: 78 template <auto kMethod> 79 void SendPacket(internal::PacketType type, 80 ConstByteSpan payload = {}, 81 Status status = OkStatus()) const { 82 using Info = internal::MethodInfo<kMethod>; 83 CheckProcessPacket( 84 type, Info::kServiceId, Info::kMethodId, payload, status); 85 } 86 87 void CheckProcessPacket(internal::PacketType type, 88 uint32_t service_id, 89 uint32_t method_id, 90 ConstByteSpan payload, 91 Status status) const; 92 93 Status ProcessPacket(internal::PacketType type, 94 uint32_t service_id, 95 uint32_t method_id, 96 ConstByteSpan payload, 97 Status status) const; 98 99 internal::test::FakeChannelOutput& output_; 100 Client& client_; 101 const uint32_t channel_id_; 102 ByteSpan packet_buffer_; // For encoding packets sent by the server 103 }; 104 105 // Instantiates a FakeServer, Client, Channel, and RawFakeChannelOutput for 106 // testing RPC client calls. These components may be used individually, but are 107 // instantiated together for convenience. 108 template <size_t kMaxPackets = 10, 109 size_t kPacketEncodeBufferSizeBytes = 128, 110 size_t kPayloadsBufferSizeBytes = 256> 111 class RawClientTestContext { 112 public: 113 static constexpr uint32_t kDefaultChannelId = 1; 114 RawClientTestContext()115 constexpr RawClientTestContext() 116 : channel_(Channel::Create<kDefaultChannelId>(&channel_output_)), 117 client_(std::span(&channel_, 1)), 118 packet_buffer_{}, 119 fake_server_( 120 channel_output_, client_, kDefaultChannelId, packet_buffer_) {} 121 channel()122 const Channel& channel() const { return channel_; } channel()123 Channel& channel() { return channel_; } 124 server()125 const FakeServer& server() const { return fake_server_; } server()126 FakeServer& server() { return fake_server_; } 127 client()128 const Client& client() const { return client_; } client()129 Client& client() { return client_; } 130 output()131 const auto& output() const { return channel_output_; } output()132 auto& output() { return channel_output_; } 133 134 private: 135 RawFakeChannelOutput<kMaxPackets, kPayloadsBufferSizeBytes> channel_output_; 136 Channel channel_; 137 Client client_; 138 std::byte packet_buffer_[kPacketEncodeBufferSizeBytes]; 139 FakeServer fake_server_; 140 }; 141 142 } // namespace pw::rpc 143