• 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 
15 // Internal-only testing utilities. public/pw_rpc/test_method_context.h provides
16 // improved public-facing utilities for testing RPC services.
17 #pragma once
18 
19 #include <array>
20 #include <cstddef>
21 #include <cstdint>
22 
23 #include "gtest/gtest.h"
24 #include "pw_assert/assert.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/raw/fake_channel_output.h"
30 #include "pw_rpc/server.h"
31 #include "pw_span/span.h"
32 
33 namespace pw::rpc::internal {
34 
35 // Version of the Server with extra methods exposed for testing.
36 class TestServer : public Server {
37  public:
38   using Server::calls_end;
39   using Server::CloseCallAndMarkForCleanup;
40   using Server::FindCall;
41 };
42 
43 template <typename Service, uint32_t kChannelId = 99, uint32_t kServiceId = 16>
44 class ServerContextForTest {
45  public:
channel_id()46   static constexpr uint32_t channel_id() { return kChannelId; }
service_id()47   static constexpr uint32_t service_id() { return kServiceId; }
48 
ServerContextForTest(const internal::Method & method)49   ServerContextForTest(const internal::Method& method)
50       : channel_(Channel::Create<kChannelId>(&output_)),
51         server_(span(&channel_, 1)),
52         service_(kServiceId),
53         context_(server_, channel_.id(), service_, method, 0) {
54     server_.RegisterService(service_);
55   }
56 
57   // Create packets for this context's channel, service, and method.
request(span<const std::byte> payload)58   internal::Packet request(span<const std::byte> payload) const {
59     return internal::Packet(internal::pwpb::PacketType::REQUEST,
60                             kChannelId,
61                             kServiceId,
62                             context_.method().id(),
63                             0,
64                             payload);
65   }
66 
67   internal::Packet response(Status status,
68                             span<const std::byte> payload = {}) const {
69     return internal::Packet(internal::pwpb::PacketType::RESPONSE,
70                             kChannelId,
71                             kServiceId,
72                             context_.method().id(),
73                             0,
74                             payload,
75                             status);
76   }
77 
server_stream(span<const std::byte> payload)78   internal::Packet server_stream(span<const std::byte> payload) const {
79     return internal::Packet(internal::pwpb::PacketType::SERVER_STREAM,
80                             kChannelId,
81                             kServiceId,
82                             context_.method().id(),
83                             0,
84                             payload);
85   }
86 
client_stream(span<const std::byte> payload)87   internal::Packet client_stream(span<const std::byte> payload) const {
88     return internal::Packet(internal::pwpb::PacketType::CLIENT_STREAM,
89                             kChannelId,
90                             kServiceId,
91                             context_.method().id(),
92                             0,
93                             payload);
94   }
95 
96   CallContext get(uint32_t id = 0) const {
97     return CallContext(context_.server(),
98                        context_.channel_id(),
99                        context_.service(),
100                        context_.method(),
101                        id);
102   }
103 
output()104   internal::test::FakeChannelOutput& output() { return output_; }
server()105   TestServer& server() { return static_cast<TestServer&>(server_); }
service()106   Service& service() { return service_; }
107 
108  private:
109   RawFakeChannelOutput<5> output_;
110   rpc::Channel channel_;
111   rpc::Server server_;
112   Service service_;
113 
114   const internal::CallContext context_;
115 };
116 
117 template <size_t kInputBufferSize = 128,
118           uint32_t kChannelId = 99,
119           uint32_t kServiceId = 16,
120           uint32_t kMethodId = 111>
121 class ClientContextForTest {
122  public:
channel_id()123   static constexpr uint32_t channel_id() { return kChannelId; }
service_id()124   static constexpr uint32_t service_id() { return kServiceId; }
method_id()125   static constexpr uint32_t method_id() { return kMethodId; }
126 
ClientContextForTest()127   ClientContextForTest()
128       : channel_(Channel::Create<kChannelId>(&output_)),
129         client_(span(&channel_, 1)) {}
130 
output()131   const internal::test::FakeChannelOutput& output() const { return output_; }
channel()132   Channel& channel() { return static_cast<Channel&>(channel_); }
client()133   Client& client() { return client_; }
134 
135   // Sends a packet to be processed by the client. Returns the client's
136   // ProcessPacket status.
137   Status SendPacket(internal::pwpb::PacketType type,
138                     Status status = OkStatus(),
139                     span<const std::byte> payload = {}) {
140     uint32_t call_id =
141         output().total_packets() > 0 ? output().last_packet().call_id() : 0;
142 
143     internal::Packet packet(
144         type, kChannelId, kServiceId, kMethodId, call_id, payload, status);
145     std::byte buffer[kInputBufferSize];
146     Result result = packet.Encode(buffer);
147     EXPECT_EQ(result.status(), OkStatus());
148     return client_.ProcessPacket(result.value_or(ConstByteSpan()));
149   }
150 
151   Status SendResponse(Status status, span<const std::byte> payload = {}) {
152     return SendPacket(internal::pwpb::PacketType::RESPONSE, status, payload);
153   }
154 
SendServerStream(span<const std::byte> payload)155   Status SendServerStream(span<const std::byte> payload) {
156     return SendPacket(
157         internal::pwpb::PacketType::SERVER_STREAM, OkStatus(), payload);
158   }
159 
160  private:
161   RawFakeChannelOutput<5> output_;
162   rpc::Channel channel_;
163   Client client_;
164 };
165 
166 }  // namespace pw::rpc::internal
167