1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/raw/internal/method.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <array>
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/algorithm.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/decoder.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/config.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/method_impl_tester.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/test_utils.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/raw/internal/method_union.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/service.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc_test_protos/test.pwpb.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard Worker namespace pw::rpc::internal {
33*61c4878aSAndroid Build Coastguard Worker namespace {
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker namespace TestRequest = ::pw::rpc::test::pwpb::TestRequest;
36*61c4878aSAndroid Build Coastguard Worker namespace TestResponse = ::pw::rpc::test::pwpb::TestResponse;
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker // Create a fake service for use with the MethodImplTester.
39*61c4878aSAndroid Build Coastguard Worker class TestRawService final : public Service {
40*61c4878aSAndroid Build Coastguard Worker public:
41*61c4878aSAndroid Build Coastguard Worker // Unary signatures
42*61c4878aSAndroid Build Coastguard Worker
Unary(ConstByteSpan,RawUnaryResponder &)43*61c4878aSAndroid Build Coastguard Worker void Unary(ConstByteSpan, RawUnaryResponder&) {}
44*61c4878aSAndroid Build Coastguard Worker
StaticUnary(ConstByteSpan,RawUnaryResponder &)45*61c4878aSAndroid Build Coastguard Worker static void StaticUnary(ConstByteSpan, RawUnaryResponder&) {}
46*61c4878aSAndroid Build Coastguard Worker
AsyncUnary(ConstByteSpan,RawUnaryResponder &)47*61c4878aSAndroid Build Coastguard Worker void AsyncUnary(ConstByteSpan, RawUnaryResponder&) {}
48*61c4878aSAndroid Build Coastguard Worker
StaticAsyncUnary(ConstByteSpan,RawUnaryResponder &)49*61c4878aSAndroid Build Coastguard Worker static void StaticAsyncUnary(ConstByteSpan, RawUnaryResponder&) {}
50*61c4878aSAndroid Build Coastguard Worker
UnaryWrongArg(ConstByteSpan,ConstByteSpan)51*61c4878aSAndroid Build Coastguard Worker void UnaryWrongArg(ConstByteSpan, ConstByteSpan) {}
52*61c4878aSAndroid Build Coastguard Worker
53*61c4878aSAndroid Build Coastguard Worker // Server streaming signatures
54*61c4878aSAndroid Build Coastguard Worker
ServerStreaming(ConstByteSpan,RawServerWriter &)55*61c4878aSAndroid Build Coastguard Worker void ServerStreaming(ConstByteSpan, RawServerWriter&) {}
56*61c4878aSAndroid Build Coastguard Worker
StaticServerStreaming(ConstByteSpan,RawServerWriter &)57*61c4878aSAndroid Build Coastguard Worker static void StaticServerStreaming(ConstByteSpan, RawServerWriter&) {}
58*61c4878aSAndroid Build Coastguard Worker
StaticUnaryVoidReturn(ConstByteSpan,ByteSpan)59*61c4878aSAndroid Build Coastguard Worker static void StaticUnaryVoidReturn(ConstByteSpan, ByteSpan) {}
60*61c4878aSAndroid Build Coastguard Worker
ServerStreamingBadReturn(ConstByteSpan,RawServerWriter &)61*61c4878aSAndroid Build Coastguard Worker Status ServerStreamingBadReturn(ConstByteSpan, RawServerWriter&) {
62*61c4878aSAndroid Build Coastguard Worker return Status();
63*61c4878aSAndroid Build Coastguard Worker }
64*61c4878aSAndroid Build Coastguard Worker
StaticServerStreamingMissingArg(RawServerWriter &)65*61c4878aSAndroid Build Coastguard Worker static void StaticServerStreamingMissingArg(RawServerWriter&) {}
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker // Client streaming signatures
68*61c4878aSAndroid Build Coastguard Worker
ClientStreaming(RawServerReader &)69*61c4878aSAndroid Build Coastguard Worker void ClientStreaming(RawServerReader&) {}
70*61c4878aSAndroid Build Coastguard Worker
StaticClientStreaming(RawServerReader &)71*61c4878aSAndroid Build Coastguard Worker static void StaticClientStreaming(RawServerReader&) {}
72*61c4878aSAndroid Build Coastguard Worker
ClientStreamingBadReturn(RawServerReader &)73*61c4878aSAndroid Build Coastguard Worker int ClientStreamingBadReturn(RawServerReader&) { return 0; }
74*61c4878aSAndroid Build Coastguard Worker
StaticClientStreamingMissingArg()75*61c4878aSAndroid Build Coastguard Worker static void StaticClientStreamingMissingArg() {}
76*61c4878aSAndroid Build Coastguard Worker
77*61c4878aSAndroid Build Coastguard Worker // Bidirectional streaming signatures
78*61c4878aSAndroid Build Coastguard Worker
BidirectionalStreaming(RawServerReaderWriter &)79*61c4878aSAndroid Build Coastguard Worker void BidirectionalStreaming(RawServerReaderWriter&) {}
80*61c4878aSAndroid Build Coastguard Worker
StaticBidirectionalStreaming(RawServerReaderWriter &)81*61c4878aSAndroid Build Coastguard Worker static void StaticBidirectionalStreaming(RawServerReaderWriter&) {}
82*61c4878aSAndroid Build Coastguard Worker
BidirectionalStreamingBadReturn(RawServerReaderWriter &)83*61c4878aSAndroid Build Coastguard Worker int BidirectionalStreamingBadReturn(RawServerReaderWriter&) { return 0; }
84*61c4878aSAndroid Build Coastguard Worker
StaticBidirectionalStreamingMissingArg()85*61c4878aSAndroid Build Coastguard Worker static void StaticBidirectionalStreamingMissingArg() {}
86*61c4878aSAndroid Build Coastguard Worker };
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard Worker static_assert(MethodImplTests<RawMethod, TestRawService>().Pass());
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard Worker template <typename Impl>
91*61c4878aSAndroid Build Coastguard Worker class FakeServiceBase : public Service {
92*61c4878aSAndroid Build Coastguard Worker public:
FakeServiceBase(uint32_t id)93*61c4878aSAndroid Build Coastguard Worker FakeServiceBase(uint32_t id) : Service(id, kMethods) {}
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard Worker static constexpr std::array<RawMethodUnion, 5> kMethods = {
96*61c4878aSAndroid Build Coastguard Worker RawMethod::AsynchronousUnary<&Impl::DoNothing>(10u),
97*61c4878aSAndroid Build Coastguard Worker RawMethod::AsynchronousUnary<&Impl::AddFive>(11u),
98*61c4878aSAndroid Build Coastguard Worker RawMethod::ServerStreaming<&Impl::StartStream>(12u),
99*61c4878aSAndroid Build Coastguard Worker RawMethod::ClientStreaming<&Impl::ClientStream>(13u),
100*61c4878aSAndroid Build Coastguard Worker RawMethod::BidirectionalStreaming<&Impl::BidirectionalStream>(14u),
101*61c4878aSAndroid Build Coastguard Worker };
102*61c4878aSAndroid Build Coastguard Worker };
103*61c4878aSAndroid Build Coastguard Worker
104*61c4878aSAndroid Build Coastguard Worker class FakeService : public FakeServiceBase<FakeService> {
105*61c4878aSAndroid Build Coastguard Worker public:
FakeService(uint32_t id)106*61c4878aSAndroid Build Coastguard Worker FakeService(uint32_t id) : FakeServiceBase(id) {}
107*61c4878aSAndroid Build Coastguard Worker
DoNothing(ConstByteSpan,RawUnaryResponder & responder)108*61c4878aSAndroid Build Coastguard Worker void DoNothing(ConstByteSpan, RawUnaryResponder& responder) {
109*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), responder.Finish({}, Status::Unknown()));
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker
AddFive(ConstByteSpan request,RawUnaryResponder & responder)112*61c4878aSAndroid Build Coastguard Worker void AddFive(ConstByteSpan request, RawUnaryResponder& responder) {
113*61c4878aSAndroid Build Coastguard Worker DecodeRawTestRequest(request);
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 32> response;
116*61c4878aSAndroid Build Coastguard Worker TestResponse::MemoryEncoder test_response(response);
117*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), test_response.WriteValue(last_request.integer + 5));
118*61c4878aSAndroid Build Coastguard Worker ConstByteSpan payload(test_response);
119*61c4878aSAndroid Build Coastguard Worker
120*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(),
121*61c4878aSAndroid Build Coastguard Worker responder.Finish(span(response).first(payload.size()),
122*61c4878aSAndroid Build Coastguard Worker Status::Unauthenticated()));
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker
StartStream(ConstByteSpan request,RawServerWriter & writer)125*61c4878aSAndroid Build Coastguard Worker void StartStream(ConstByteSpan request, RawServerWriter& writer) {
126*61c4878aSAndroid Build Coastguard Worker DecodeRawTestRequest(request);
127*61c4878aSAndroid Build Coastguard Worker last_writer = std::move(writer);
128*61c4878aSAndroid Build Coastguard Worker }
129*61c4878aSAndroid Build Coastguard Worker
ClientStream(RawServerReader & reader)130*61c4878aSAndroid Build Coastguard Worker void ClientStream(RawServerReader& reader) {
131*61c4878aSAndroid Build Coastguard Worker last_reader = std::move(reader);
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker
BidirectionalStream(RawServerReaderWriter & reader_writer)134*61c4878aSAndroid Build Coastguard Worker void BidirectionalStream(RawServerReaderWriter& reader_writer) {
135*61c4878aSAndroid Build Coastguard Worker last_reader_writer = std::move(reader_writer);
136*61c4878aSAndroid Build Coastguard Worker }
137*61c4878aSAndroid Build Coastguard Worker
DecodeRawTestRequest(ConstByteSpan request)138*61c4878aSAndroid Build Coastguard Worker void DecodeRawTestRequest(ConstByteSpan request) {
139*61c4878aSAndroid Build Coastguard Worker protobuf::Decoder decoder(request);
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker while (decoder.Next().ok()) {
142*61c4878aSAndroid Build Coastguard Worker TestRequest::Fields field =
143*61c4878aSAndroid Build Coastguard Worker static_cast<TestRequest::Fields>(decoder.FieldNumber());
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard Worker switch (field) {
146*61c4878aSAndroid Build Coastguard Worker case TestRequest::Fields::kInteger:
147*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), decoder.ReadInt64(&last_request.integer));
148*61c4878aSAndroid Build Coastguard Worker break;
149*61c4878aSAndroid Build Coastguard Worker case TestRequest::Fields::kStatusCode:
150*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), decoder.ReadUint32(&last_request.status_code));
151*61c4878aSAndroid Build Coastguard Worker break;
152*61c4878aSAndroid Build Coastguard Worker }
153*61c4878aSAndroid Build Coastguard Worker }
154*61c4878aSAndroid Build Coastguard Worker }
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker struct {
157*61c4878aSAndroid Build Coastguard Worker int64_t integer;
158*61c4878aSAndroid Build Coastguard Worker uint32_t status_code;
159*61c4878aSAndroid Build Coastguard Worker } last_request;
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker RawServerWriter last_writer;
162*61c4878aSAndroid Build Coastguard Worker RawServerReader last_reader;
163*61c4878aSAndroid Build Coastguard Worker RawServerReaderWriter last_reader_writer;
164*61c4878aSAndroid Build Coastguard Worker };
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker constexpr const RawMethod& kAsyncUnary0 =
167*61c4878aSAndroid Build Coastguard Worker std::get<0>(FakeServiceBase<FakeService>::kMethods).raw_method();
168*61c4878aSAndroid Build Coastguard Worker constexpr const RawMethod& kAsyncUnary1 =
169*61c4878aSAndroid Build Coastguard Worker std::get<1>(FakeServiceBase<FakeService>::kMethods).raw_method();
170*61c4878aSAndroid Build Coastguard Worker constexpr const RawMethod& kServerStream =
171*61c4878aSAndroid Build Coastguard Worker std::get<2>(FakeServiceBase<FakeService>::kMethods).raw_method();
172*61c4878aSAndroid Build Coastguard Worker constexpr const RawMethod& kClientStream =
173*61c4878aSAndroid Build Coastguard Worker std::get<3>(FakeServiceBase<FakeService>::kMethods).raw_method();
174*61c4878aSAndroid Build Coastguard Worker constexpr const RawMethod& kBidirectionalStream =
175*61c4878aSAndroid Build Coastguard Worker std::get<4>(FakeServiceBase<FakeService>::kMethods).raw_method();
176*61c4878aSAndroid Build Coastguard Worker
TEST(RawMethod,AsyncUnaryRpc1_SendsResponse)177*61c4878aSAndroid Build Coastguard Worker TEST(RawMethod, AsyncUnaryRpc1_SendsResponse) {
178*61c4878aSAndroid Build Coastguard Worker std::byte buffer[16];
179*61c4878aSAndroid Build Coastguard Worker stream::MemoryWriter writer(buffer);
180*61c4878aSAndroid Build Coastguard Worker TestRequest::StreamEncoder test_request(writer, ByteSpan());
181*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), test_request.WriteInteger(456));
182*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), test_request.WriteStatusCode(7));
183*61c4878aSAndroid Build Coastguard Worker
184*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kAsyncUnary1);
185*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
186*61c4878aSAndroid Build Coastguard Worker kAsyncUnary1.Invoke(context.get(), context.request(writer.WrittenData()));
187*61c4878aSAndroid Build Coastguard Worker
188*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service().last_request.integer, 456);
189*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service().last_request.status_code, 7u);
190*61c4878aSAndroid Build Coastguard Worker
191*61c4878aSAndroid Build Coastguard Worker const Packet& response = context.output().last_packet();
192*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(response.status(), Status::Unauthenticated());
193*61c4878aSAndroid Build Coastguard Worker
194*61c4878aSAndroid Build Coastguard Worker protobuf::Decoder decoder(response.payload());
195*61c4878aSAndroid Build Coastguard Worker ASSERT_TRUE(decoder.Next().ok());
196*61c4878aSAndroid Build Coastguard Worker int64_t value;
197*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt64(&value), OkStatus());
198*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(value, 461);
199*61c4878aSAndroid Build Coastguard Worker }
200*61c4878aSAndroid Build Coastguard Worker
TEST(RawMethod,AsyncUnaryRpc0_SendsResponse)201*61c4878aSAndroid Build Coastguard Worker TEST(RawMethod, AsyncUnaryRpc0_SendsResponse) {
202*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kAsyncUnary0);
203*61c4878aSAndroid Build Coastguard Worker
204*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
205*61c4878aSAndroid Build Coastguard Worker kAsyncUnary0.Invoke(context.get(), context.request({}));
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker const Packet& packet = context.output().last_packet();
208*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(pwpb::PacketType::RESPONSE, packet.type());
209*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(Status::Unknown(), packet.status());
210*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service_id(), packet.service_id());
211*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(kAsyncUnary0.id(), packet.method_id());
212*61c4878aSAndroid Build Coastguard Worker }
213*61c4878aSAndroid Build Coastguard Worker
TEST(RawMethod,ServerStreamingRpc_SendsNothingWhenInitiallyCalled)214*61c4878aSAndroid Build Coastguard Worker TEST(RawMethod, ServerStreamingRpc_SendsNothingWhenInitiallyCalled) {
215*61c4878aSAndroid Build Coastguard Worker std::byte buffer[16];
216*61c4878aSAndroid Build Coastguard Worker stream::MemoryWriter writer(buffer);
217*61c4878aSAndroid Build Coastguard Worker TestRequest::StreamEncoder test_request(writer, ByteSpan());
218*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), test_request.WriteInteger(777));
219*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), test_request.WriteStatusCode(2));
220*61c4878aSAndroid Build Coastguard Worker
221*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kServerStream);
222*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
223*61c4878aSAndroid Build Coastguard Worker kServerStream.Invoke(context.get(), context.request(writer.WrittenData()));
224*61c4878aSAndroid Build Coastguard Worker
225*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(0u, context.output().total_packets());
226*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(777, context.service().last_request.integer);
227*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(2u, context.service().last_request.status_code);
228*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(context.service().last_writer.active());
229*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), context.service().last_writer.Finish());
230*61c4878aSAndroid Build Coastguard Worker }
231*61c4878aSAndroid Build Coastguard Worker
TEST(RawMethod,ServerReader_HandlesRequests)232*61c4878aSAndroid Build Coastguard Worker TEST(RawMethod, ServerReader_HandlesRequests) {
233*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kClientStream);
234*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
235*61c4878aSAndroid Build Coastguard Worker kClientStream.Invoke(context.get(), context.request({}));
236*61c4878aSAndroid Build Coastguard Worker
237*61c4878aSAndroid Build Coastguard Worker ConstByteSpan request;
238*61c4878aSAndroid Build Coastguard Worker context.service().last_reader.set_on_next(
239*61c4878aSAndroid Build Coastguard Worker [&request](ConstByteSpan req) { request = req; });
240*61c4878aSAndroid Build Coastguard Worker
241*61c4878aSAndroid Build Coastguard Worker constexpr const char kRequestValue[] = "This is a request payload!!!";
242*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 128> encoded_request = {};
243*61c4878aSAndroid Build Coastguard Worker auto encoded = context.client_stream(as_bytes(span(kRequestValue)))
244*61c4878aSAndroid Build Coastguard Worker .Encode(encoded_request);
245*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), encoded.status());
246*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), context.server().ProcessPacket(*encoded));
247*61c4878aSAndroid Build Coastguard Worker
248*61c4878aSAndroid Build Coastguard Worker EXPECT_STREQ(reinterpret_cast<const char*>(request.data()), kRequestValue);
249*61c4878aSAndroid Build Coastguard Worker }
250*61c4878aSAndroid Build Coastguard Worker
TEST(RawMethod,ServerReaderWriter_WritesResponses)251*61c4878aSAndroid Build Coastguard Worker TEST(RawMethod, ServerReaderWriter_WritesResponses) {
252*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kBidirectionalStream);
253*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
254*61c4878aSAndroid Build Coastguard Worker kBidirectionalStream.Invoke(context.get(), context.request({}));
255*61c4878aSAndroid Build Coastguard Worker
256*61c4878aSAndroid Build Coastguard Worker constexpr const char kRequestValue[] = "O_o";
257*61c4878aSAndroid Build Coastguard Worker const auto kRequestBytes = as_bytes(span(kRequestValue));
258*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(),
259*61c4878aSAndroid Build Coastguard Worker context.service().last_reader_writer.Write(kRequestBytes));
260*61c4878aSAndroid Build Coastguard Worker
261*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 128> encoded_response = {};
262*61c4878aSAndroid Build Coastguard Worker auto encoded = context.server_stream(kRequestBytes).Encode(encoded_response);
263*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(OkStatus(), encoded.status());
264*61c4878aSAndroid Build Coastguard Worker
265*61c4878aSAndroid Build Coastguard Worker ConstByteSpan sent_payload = context.output().last_packet().payload();
266*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(pw::containers::Equal(kRequestBytes, sent_payload));
267*61c4878aSAndroid Build Coastguard Worker }
268*61c4878aSAndroid Build Coastguard Worker
TEST(RawServerWriter,Write_SendsPayload)269*61c4878aSAndroid Build Coastguard Worker TEST(RawServerWriter, Write_SendsPayload) {
270*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kServerStream);
271*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
272*61c4878aSAndroid Build Coastguard Worker kServerStream.Invoke(context.get(), context.request({}));
273*61c4878aSAndroid Build Coastguard Worker
274*61c4878aSAndroid Build Coastguard Worker constexpr auto data = bytes::Array<0x0d, 0x06, 0xf0, 0x0d>();
275*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service().last_writer.Write(data), OkStatus());
276*61c4878aSAndroid Build Coastguard Worker
277*61c4878aSAndroid Build Coastguard Worker const internal::Packet& packet = context.output().last_packet();
278*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.type(), pwpb::PacketType::SERVER_STREAM);
279*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.channel_id(), context.channel_id());
280*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.service_id(), context.service_id());
281*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.method_id(), context.get().method().id());
282*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(std::memcmp(packet.payload().data(), data.data(), data.size()), 0);
283*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.status(), OkStatus());
284*61c4878aSAndroid Build Coastguard Worker }
285*61c4878aSAndroid Build Coastguard Worker
TEST(RawServerWriter,Write_EmptyBuffer)286*61c4878aSAndroid Build Coastguard Worker TEST(RawServerWriter, Write_EmptyBuffer) {
287*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kServerStream);
288*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
289*61c4878aSAndroid Build Coastguard Worker kServerStream.Invoke(context.get(), context.request({}));
290*61c4878aSAndroid Build Coastguard Worker
291*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(context.service().last_writer.Write(ConstByteSpan()), OkStatus());
292*61c4878aSAndroid Build Coastguard Worker
293*61c4878aSAndroid Build Coastguard Worker const internal::Packet& packet = context.output().last_packet();
294*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.type(), pwpb::PacketType::SERVER_STREAM);
295*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.channel_id(), context.channel_id());
296*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.service_id(), context.service_id());
297*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.method_id(), context.get().method().id());
298*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(packet.payload().empty());
299*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(packet.status(), OkStatus());
300*61c4878aSAndroid Build Coastguard Worker }
301*61c4878aSAndroid Build Coastguard Worker
TEST(RawServerWriter,Write_Closed_ReturnsFailedPrecondition)302*61c4878aSAndroid Build Coastguard Worker TEST(RawServerWriter, Write_Closed_ReturnsFailedPrecondition) {
303*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kServerStream);
304*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
305*61c4878aSAndroid Build Coastguard Worker kServerStream.Invoke(context.get(), context.request({}));
306*61c4878aSAndroid Build Coastguard Worker
307*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), context.service().last_writer.Finish());
308*61c4878aSAndroid Build Coastguard Worker constexpr auto data = bytes::Array<0x0d, 0x06, 0xf0, 0x0d>();
309*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service().last_writer.Write(data),
310*61c4878aSAndroid Build Coastguard Worker Status::FailedPrecondition());
311*61c4878aSAndroid Build Coastguard Worker }
312*61c4878aSAndroid Build Coastguard Worker
TEST(RawServerWriter,Write_PayloadTooLargeForEncodingBuffer_ReturnsInternal)313*61c4878aSAndroid Build Coastguard Worker TEST(RawServerWriter, Write_PayloadTooLargeForEncodingBuffer_ReturnsInternal) {
314*61c4878aSAndroid Build Coastguard Worker // The payload is never too large for the encoding buffer when dynamic
315*61c4878aSAndroid Build Coastguard Worker // allocation is enabled.
316*61c4878aSAndroid Build Coastguard Worker #if PW_RPC_DYNAMIC_ALLOCATION
317*61c4878aSAndroid Build Coastguard Worker GTEST_SKIP();
318*61c4878aSAndroid Build Coastguard Worker #endif // !PW_RPC_DYNAMIC_ALLOCATION
319*61c4878aSAndroid Build Coastguard Worker
320*61c4878aSAndroid Build Coastguard Worker ServerContextForTest<FakeService> context(kServerStream);
321*61c4878aSAndroid Build Coastguard Worker rpc_lock().lock();
322*61c4878aSAndroid Build Coastguard Worker kServerStream.Invoke(context.get(), context.request({}));
323*61c4878aSAndroid Build Coastguard Worker
324*61c4878aSAndroid Build Coastguard Worker // A kEncodingBufferSizeBytes payload will never fit in the encoding buffer.
325*61c4878aSAndroid Build Coastguard Worker static constexpr std::array<std::byte, cfg::kEncodingBufferSizeBytes>
326*61c4878aSAndroid Build Coastguard Worker kBigData = {};
327*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(context.service().last_writer.Write(kBigData), Status::Internal());
328*61c4878aSAndroid Build Coastguard Worker }
329*61c4878aSAndroid Build Coastguard Worker
330*61c4878aSAndroid Build Coastguard Worker } // namespace
331*61c4878aSAndroid Build Coastguard Worker } // namespace pw::rpc::internal
332