C/C++ API Reference
Loading...
Searching...
No Matches
payloads_view.h
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// The classes in this file facilitate testing RPC services. The main class is
16// PayloadsView, which iterates over the payloads sent by an RPC service or
17// client. This allows verifying that code that invokes RPCs or an RPC service
18// implementation sends the expected requests or responses.
19//
20// This code is inteded for testing, not for deployment.
21#pragma once
22
23#include <tuple>
24
25#include "pw_containers/filtered_view.h"
26#include "pw_containers/vector.h"
27#include "pw_containers/wrapped_iterator.h"
28#include "pw_rpc/channel.h"
29#include "pw_rpc/internal/method_info.h"
30#include "pw_rpc/internal/packet.h"
31#include "pw_rpc/method_type.h"
32
33namespace pw::rpc {
34namespace internal::test {
35
36class FakeChannelOutput;
37
38// Finds packets of a specified type for a particular method.
40 public:
41 // Use Channel::kUnassignedChannelId to ignore the channel.
42 constexpr PacketFilter(internal::pwpb::PacketType packet_type_1,
43 internal::pwpb::PacketType packet_type_2,
44 uint32_t channel_id,
45 uint32_t service_id,
46 uint32_t method_id)
47 : packet_type_1_(packet_type_1),
48 packet_type_2_(packet_type_2),
49 channel_id_(channel_id),
50 service_id_(service_id),
51 method_id_(method_id) {}
52
53 constexpr bool operator()(const Packet& packet) const {
54 return (packet.type() == packet_type_1_ ||
55 packet.type() == packet_type_2_) &&
56 (channel_id_ == Channel::kUnassignedChannelId ||
57 packet.channel_id() == channel_id_) &&
58 packet.service_id() == service_id_ &&
59 packet.method_id() == method_id_;
60 }
61
62 private:
63 // Support filtering on two packet types to handle reading both client and
64 // server streams for bidirectional streams.
65 internal::pwpb::PacketType packet_type_1_;
66 internal::pwpb::PacketType packet_type_2_;
67 uint32_t channel_id_;
68 uint32_t service_id_;
69 uint32_t method_id_;
70};
71
73
74} // namespace internal::test
75
77
78// Returns the payloads for a particular RPC in a Vector of RPC packets.
79//
80// Adapts a FilteredView of packets to return payloads instead of packets.
82 public:
84 iterator,
85 internal::test::PacketsView::iterator,
86 ConstByteSpan> {
87 public:
88 constexpr iterator() = default;
89
90 // Access the payload (rather than packet) with operator* and operator->.
91 const ConstByteSpan& operator*() const { return value().payload(); }
92 const ConstByteSpan* operator->() const { return &value().payload(); }
93
94 private:
95 friend class PayloadsView;
96
97 constexpr iterator(const internal::test::PacketsView::iterator& it)
99 internal::test::PacketsView::iterator,
100 ConstByteSpan>(it) {}
101 };
102
103 using const_iterator = iterator;
104
105 const ConstByteSpan& operator[](size_t index) const {
106 auto it = begin();
107 std::advance(it, index);
108 return *it;
109 }
110
111 // Number of payloads for the specified RPC.
112 size_t size() const { return view_.size(); }
113
114 bool empty() const { return begin() == end(); }
115
116 // Returns the first/last payload for the RPC. size() must be > 0.
117 const ConstByteSpan& front() const { return *begin(); }
118 const ConstByteSpan& back() const { return *std::prev(end()); }
119
120 iterator begin() const { return iterator(view_.begin()); }
121 iterator end() const { return iterator(view_.end()); }
122
123 private:
124 friend class internal::test::FakeChannelOutput;
125
126 template <typename>
127 friend class NanopbPayloadsView;
128
129 template <typename>
130 friend class PwpbPayloadsView;
131
132 template <auto kMethod>
133 using MethodInfo = internal::MethodInfo<kMethod>;
134
135 using PacketType = internal::pwpb::PacketType;
136
137 template <auto kMethod>
138 static constexpr PayloadsView For(const Vector<internal::Packet>& packets,
139 uint32_t channel_id) {
140 constexpr auto kTypes = PacketTypesWithPayload(MethodInfo<kMethod>::kType);
141 return PayloadsView(packets,
142 std::get<0>(kTypes),
143 std::get<1>(kTypes),
144 channel_id,
145 MethodInfo<kMethod>::kServiceId,
146 MethodInfo<kMethod>::kMethodId);
147 }
148
149 constexpr PayloadsView(const Vector<internal::Packet>& packets,
150 MethodType method_type,
151 uint32_t channel_id,
152 uint32_t service_id,
153 uint32_t method_id)
154 : PayloadsView(packets,
155 std::get<0>(PacketTypesWithPayload(method_type)),
156 std::get<1>(PacketTypesWithPayload(method_type)),
157 channel_id,
158 service_id,
159 method_id) {}
160
161 constexpr PayloadsView(const Vector<internal::Packet>& packets,
162 PacketType packet_type_1,
163 PacketType packet_type_2,
164 uint32_t channel_id,
165 uint32_t service_id,
166 uint32_t method_id)
167 : view_(packets,
168 internal::test::PacketFilter(packet_type_1,
169 packet_type_2,
170 channel_id,
171 service_id,
172 method_id)) {}
173
174 static constexpr std::tuple<PacketType, PacketType> PacketTypesWithPayload(
175 MethodType method_type) {
176 switch (method_type) {
177 case MethodType::kUnary:
178 return {PacketType::REQUEST, PacketType::RESPONSE};
179 case MethodType::kServerStreaming:
180 return {PacketType::REQUEST, PacketType::SERVER_STREAM};
181 case MethodType::kClientStreaming:
182 return {PacketType::CLIENT_STREAM, PacketType::RESPONSE};
183 case MethodType::kBidirectionalStreaming:
184 return {PacketType::CLIENT_STREAM, PacketType::SERVER_STREAM};
185 }
186
187// Workaround for GCC 8 bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86678
188#if defined(__GNUC__) && __GNUC__ < 9
189 return {};
190#else
191 PW_ASSERT(false);
192#endif // defined(__GNUC__) && __GNUC__ < 9
193 }
194
195 internal::test::PacketsView view_;
196};
197
198// Class for iterating over RPC statuses associated witha particular RPC. This
199// is used to iterate over the user RPC statuses and or protocol errors for a
200// particular RPC.
202 public:
204 iterator,
205 internal::test::PacketsView::iterator,
206 Status> {
207 public:
208 constexpr iterator() = default;
209
210 // Access the status (rather than packet) with operator* and operator->.
211 const Status& operator*() const { return value().status(); }
212 const Status* operator->() const { return &value().status(); }
213
214 private:
215 friend class StatusView;
216
217 constexpr iterator(const internal::test::PacketsView::iterator& it)
219 internal::test::PacketsView::iterator,
220 Status>(it) {}
221 };
222
223 using const_iterator = iterator;
224
225 const Status& operator[](size_t index) const {
226 auto it = begin();
227 std::advance(it, index);
228 return *it;
229 }
230
231 // Number of statuses in this view.
232 size_t size() const { return view_.size(); }
233 bool empty() const { return begin() == end(); }
234
235 // Returns the first/last payload for the RPC. size() must be > 0.
236 const Status& front() const { return *begin(); }
237 const Status& back() const { return *std::prev(end()); }
238
239 iterator begin() const { return iterator(view_.begin()); }
240 iterator end() const { return iterator(view_.end()); }
241
242 private:
243 friend class internal::test::FakeChannelOutput;
244
245 template <auto kMethod>
246 using MethodInfo = internal::MethodInfo<kMethod>;
247
248 using PacketType = internal::pwpb::PacketType;
249
250 constexpr StatusView(const Vector<internal::Packet>& packets,
251 PacketType packet_type_1,
252 PacketType packet_type_2,
253 uint32_t channel_id,
254 uint32_t service_id,
255 uint32_t method_id)
256 : view_(packets,
257 internal::test::PacketFilter(packet_type_1,
258 packet_type_2,
259 channel_id,
260 service_id,
261 method_id)) {}
262
263 internal::test::PacketsView view_;
264};
265
267
268} // namespace pw::rpc
Definition: status.h:109
Definition: wrapped_iterator.h:34
Definition: payloads_view.h:86
Definition: payloads_view.h:81
Definition: payloads_view.h:206
Definition: payloads_view.h:201
Definition: payloads_view.h:39