• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 "pw_assert/light.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/internal/server.h"
30 
31 namespace pw::rpc {
32 
33 template <size_t kOutputBufferSize>
34 class TestOutput : public ChannelOutput {
35  public:
buffer_size()36   static constexpr size_t buffer_size() { return kOutputBufferSize; }
37 
38   constexpr TestOutput(const char* name = "TestOutput")
ChannelOutput(name)39       : ChannelOutput(name), sent_data_{} {}
40 
AcquireBuffer()41   std::span<std::byte> AcquireBuffer() override { return buffer_; }
42 
SendAndReleaseBuffer(std::span<const std::byte> buffer)43   Status SendAndReleaseBuffer(std::span<const std::byte> buffer) override {
44     if (buffer.empty()) {
45       return OkStatus();
46     }
47 
48     PW_ASSERT(buffer.data() == buffer_.data());
49 
50     packet_count_ += 1;
51     sent_data_ = buffer;
52     Result<internal::Packet> result = internal::Packet::FromBuffer(sent_data_);
53     EXPECT_EQ(OkStatus(), result.status());
54     sent_packet_ = result.value_or(internal::Packet());
55     return send_status_;
56   }
57 
buffer()58   std::span<const std::byte> buffer() const { return buffer_; }
59 
packet_count()60   size_t packet_count() const { return packet_count_; }
61 
set_send_status(Status status)62   void set_send_status(Status status) { send_status_ = status; }
63 
sent_data()64   const std::span<const std::byte>& sent_data() const { return sent_data_; }
sent_packet()65   const internal::Packet& sent_packet() const {
66     EXPECT_GT(packet_count_, 0u);
67     return sent_packet_;
68   }
69 
70  private:
71   std::array<std::byte, buffer_size()> buffer_;
72   std::span<const std::byte> sent_data_;
73   internal::Packet sent_packet_;
74   size_t packet_count_ = 0;
75   Status send_status_;
76 };
77 
78 // Version of the internal::Server with extra methods exposed for testing.
79 class TestServer : public internal::Server {
80  public:
81   using internal::Server::writers;
82 };
83 
84 template <typename Service,
85           size_t kOutputBufferSize = 128,
86           uint32_t kChannelId = 99,
87           uint32_t kServiceId = 16>
88 class ServerContextForTest {
89  public:
channel_id()90   static constexpr uint32_t channel_id() { return kChannelId; }
service_id()91   static constexpr uint32_t service_id() { return kServiceId; }
92 
ServerContextForTest(const internal::Method & method)93   ServerContextForTest(const internal::Method& method)
94       : channel_(Channel::Create<kChannelId>(&output_)),
95         server_(std::span(&channel_, 1)),
96         service_(kServiceId),
97         context_(static_cast<internal::Server&>(server_),
98                  static_cast<internal::Channel&>(channel_),
99                  service_,
100                  method) {
101     server_.RegisterService(service_);
102   }
103 
104   // Creates a response packet for this context's channel, service, and method.
packet(std::span<const std::byte> payload)105   internal::Packet packet(std::span<const std::byte> payload) const {
106     return internal::Packet(internal::PacketType::RESPONSE,
107                             kChannelId,
108                             kServiceId,
109                             context_.method().id(),
110                             payload,
111                             OkStatus());
112   }
113 
get()114   internal::ServerCall& get() { return context_; }
output()115   auto& output() { return output_; }
server()116   TestServer& server() { return static_cast<TestServer&>(server_); }
117 
118  private:
119   TestOutput<kOutputBufferSize> output_;
120   Channel channel_;
121   Server server_;
122   Service service_;
123 
124   internal::ServerCall context_;
125 };
126 
127 template <size_t kOutputBufferSize = 128,
128           size_t input_buffer_size = 128,
129           uint32_t kChannelId = 99,
130           uint32_t kServiceId = 16,
131           uint32_t kMethodId = 111>
132 class ClientContextForTest {
133  public:
channel_id()134   static constexpr uint32_t channel_id() { return kChannelId; }
service_id()135   static constexpr uint32_t service_id() { return kServiceId; }
method_id()136   static constexpr uint32_t method_id() { return kMethodId; }
137 
ClientContextForTest()138   ClientContextForTest()
139       : channel_(Channel::Create<kChannelId>(&output_)),
140         client_(std::span(&channel_, 1)) {}
141 
output()142   const auto& output() const { return output_; }
channel()143   Channel& channel() { return channel_; }
client()144   Client& client() { return client_; }
145 
146   // Sends a packet to be processed by the client. Returns the client's
147   // ProcessPacket status.
148   Status SendPacket(internal::PacketType type,
149                     Status status = OkStatus(),
150                     std::span<const std::byte> payload = {}) {
151     internal::Packet packet(
152         type, kChannelId, kServiceId, kMethodId, payload, status);
153     std::byte buffer[input_buffer_size];
154     Result result = packet.Encode(buffer);
155     EXPECT_EQ(result.status(), OkStatus());
156     return client_.ProcessPacket(result.value_or(ConstByteSpan()));
157   }
158 
SendResponse(Status status,std::span<const std::byte> payload)159   Status SendResponse(Status status, std::span<const std::byte> payload) {
160     return SendPacket(internal::PacketType::RESPONSE, status, payload);
161   }
162 
163  private:
164   TestOutput<kOutputBufferSize> output_;
165   Channel channel_;
166   Client client_;
167 };
168 
169 }  // namespace pw::rpc
170