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