• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(b/234878467): 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)>>
48   void SendResponse(Status status,
49                     std::optional<uint32_t> call_id = std::nullopt) const {
50     SendPacket<kMethod>(
51         internal::pwpb::PacketType::RESPONSE, {}, status, call_id);
52   }
53 
54   // Sends a response packet for a unary or client streaming streaming RPC to
55   // the client.
56   template <auto kMethod,
57             typename = std::enable_if_t<
58                 !HasServerStream(internal::MethodInfo<kMethod>::kType)>>
59   void SendResponse(ConstByteSpan payload,
60                     Status status,
61                     std::optional<uint32_t> call_id = std::nullopt) const {
62     SendPacket<kMethod>(
63         internal::pwpb::PacketType::RESPONSE, payload, status, call_id);
64   }
65 
66   // Sends a stream packet for a server or bidirectional streaming RPC to the
67   // client.
68   template <auto kMethod>
69   void SendServerStream(ConstByteSpan payload,
70                         std::optional<uint32_t> call_id = std::nullopt) const {
71     static_assert(HasServerStream(internal::MethodInfo<kMethod>::kType),
72                   "Only server and bidirectional streaming methods can receive "
73                   "server stream packets");
74     SendPacket<kMethod>(internal::pwpb::PacketType::SERVER_STREAM,
75                         payload,
76                         OkStatus(),
77                         call_id);
78   }
79 
80   // Sends a server error packet to the client.
81   template <auto kMethod>
82   void SendServerError(Status error,
83                        std::optional<uint32_t> call_id = std::nullopt) const {
84     SendPacket<kMethod>(
85         internal::pwpb::PacketType::SERVER_ERROR, {}, error, call_id);
86   }
87 
88  private:
89   template <auto kMethod>
SendPacket(internal::pwpb::PacketType type,ConstByteSpan payload,Status status,std::optional<uint32_t> call_id)90   void SendPacket(internal::pwpb::PacketType type,
91                   ConstByteSpan payload,
92                   Status status,
93                   std::optional<uint32_t> call_id) const {
94     using Info = internal::MethodInfo<kMethod>;
95     CheckProcessPacket(
96         type, Info::kServiceId, Info::kMethodId, call_id, payload, status);
97   }
98 
99   void CheckProcessPacket(internal::pwpb::PacketType type,
100                           uint32_t service_id,
101                           uint32_t method_id,
102                           std::optional<uint32_t> call_id,
103                           ConstByteSpan payload,
104                           Status status) const;
105 
106   Status ProcessPacket(internal::pwpb::PacketType type,
107                        uint32_t service_id,
108                        uint32_t method_id,
109                        std::optional<uint32_t> call_id,
110                        ConstByteSpan payload,
111                        Status status) const;
112 
113   internal::test::FakeChannelOutput& output_;
114   Client& client_;
115   const uint32_t channel_id_;
116   ByteSpan packet_buffer_;  // For encoding packets sent by the server
117 };
118 
119 // Instantiates a FakeServer, Client, Channel, and RawFakeChannelOutput for
120 // testing RPC client calls. These components may be used individually, but are
121 // instantiated together for convenience.
122 template <size_t kMaxPackets = 10,
123           size_t kPacketEncodeBufferSizeBytes = 128,
124           size_t kPayloadsBufferSizeBytes = 256>
125 class RawClientTestContext {
126  public:
127   static constexpr uint32_t kDefaultChannelId = 1;
128 
RawClientTestContext()129   constexpr RawClientTestContext()
130       : channel_(Channel::Create<kDefaultChannelId>(&channel_output_)),
131         client_(span(&channel_, 1)),
132         packet_buffer_{},
133         fake_server_(
134             channel_output_, client_, kDefaultChannelId, packet_buffer_) {}
135 
channel()136   const Channel& channel() const { return channel_; }
channel()137   Channel& channel() { return channel_; }
138 
server()139   const FakeServer& server() const { return fake_server_; }
server()140   FakeServer& server() { return fake_server_; }
141 
client()142   const Client& client() const { return client_; }
client()143   Client& client() { return client_; }
144 
output()145   const auto& output() const { return channel_output_; }
output()146   auto& output() { return channel_output_; }
147 
148  private:
149   RawFakeChannelOutput<kMaxPackets, kPayloadsBufferSizeBytes> channel_output_;
150   Channel channel_;
151   Client client_;
152   std::byte packet_buffer_[kPacketEncodeBufferSizeBytes];
153   FakeServer fake_server_;
154 };
155 
156 }  // namespace pw::rpc
157