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