xref: /aosp_15_r20/external/pigweed/pw_rpc/nanopb/method_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/nanopb/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_containers/algorithm.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/lock.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/method_impl_tester.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/test_utils.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/nanopb/internal/method_union.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/service.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc_nanopb_private/internal_test_utils.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc_test_protos/test.pb.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
28*61c4878aSAndroid Build Coastguard Worker 
29*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTICS_PUSH();
30*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers");
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 using std::byte;
36*61c4878aSAndroid Build Coastguard Worker 
37*61c4878aSAndroid Build Coastguard Worker struct FakePb {};
38*61c4878aSAndroid Build Coastguard Worker 
39*61c4878aSAndroid Build Coastguard Worker // Create a fake service for use with the MethodImplTester.
40*61c4878aSAndroid Build Coastguard Worker class TestNanopbService final : public Service {
41*61c4878aSAndroid Build Coastguard Worker  public:
42*61c4878aSAndroid Build Coastguard Worker   // Unary signatures
43*61c4878aSAndroid Build Coastguard Worker 
Unary(const FakePb &,FakePb &)44*61c4878aSAndroid Build Coastguard Worker   Status Unary(const FakePb&, FakePb&) { return Status(); }
45*61c4878aSAndroid Build Coastguard Worker 
StaticUnary(const FakePb &,FakePb &)46*61c4878aSAndroid Build Coastguard Worker   static Status StaticUnary(const FakePb&, FakePb&) { return Status(); }
47*61c4878aSAndroid Build Coastguard Worker 
AsyncUnary(const FakePb &,NanopbUnaryResponder<FakePb> &)48*61c4878aSAndroid Build Coastguard Worker   void AsyncUnary(const FakePb&, NanopbUnaryResponder<FakePb>&) {}
49*61c4878aSAndroid Build Coastguard Worker 
StaticAsyncUnary(const FakePb &,NanopbUnaryResponder<FakePb> &)50*61c4878aSAndroid Build Coastguard Worker   static void StaticAsyncUnary(const FakePb&, NanopbUnaryResponder<FakePb>&) {}
51*61c4878aSAndroid Build Coastguard Worker 
UnaryWrongArg(FakePb &,FakePb &)52*61c4878aSAndroid Build Coastguard Worker   Status UnaryWrongArg(FakePb&, FakePb&) { return Status(); }
53*61c4878aSAndroid Build Coastguard Worker 
StaticUnaryVoidReturn(const FakePb &,FakePb &)54*61c4878aSAndroid Build Coastguard Worker   static void StaticUnaryVoidReturn(const FakePb&, FakePb&) {}
55*61c4878aSAndroid Build Coastguard Worker 
56*61c4878aSAndroid Build Coastguard Worker   // Server streaming signatures
57*61c4878aSAndroid Build Coastguard Worker 
ServerStreaming(const FakePb &,NanopbServerWriter<FakePb> &)58*61c4878aSAndroid Build Coastguard Worker   void ServerStreaming(const FakePb&, NanopbServerWriter<FakePb>&) {}
59*61c4878aSAndroid Build Coastguard Worker 
StaticServerStreaming(const FakePb &,NanopbServerWriter<FakePb> &)60*61c4878aSAndroid Build Coastguard Worker   static void StaticServerStreaming(const FakePb&,
61*61c4878aSAndroid Build Coastguard Worker                                     NanopbServerWriter<FakePb>&) {}
62*61c4878aSAndroid Build Coastguard Worker 
ServerStreamingBadReturn(const FakePb &,NanopbServerWriter<FakePb> &)63*61c4878aSAndroid Build Coastguard Worker   int ServerStreamingBadReturn(const FakePb&, NanopbServerWriter<FakePb>&) {
64*61c4878aSAndroid Build Coastguard Worker     return 5;
65*61c4878aSAndroid Build Coastguard Worker   }
66*61c4878aSAndroid Build Coastguard Worker 
StaticServerStreamingMissingArg(NanopbServerWriter<FakePb> &)67*61c4878aSAndroid Build Coastguard Worker   static void StaticServerStreamingMissingArg(NanopbServerWriter<FakePb>&) {}
68*61c4878aSAndroid Build Coastguard Worker 
69*61c4878aSAndroid Build Coastguard Worker   // Client streaming signatures
70*61c4878aSAndroid Build Coastguard Worker 
ClientStreaming(NanopbServerReader<FakePb,FakePb> &)71*61c4878aSAndroid Build Coastguard Worker   void ClientStreaming(NanopbServerReader<FakePb, FakePb>&) {}
72*61c4878aSAndroid Build Coastguard Worker 
StaticClientStreaming(NanopbServerReader<FakePb,FakePb> &)73*61c4878aSAndroid Build Coastguard Worker   static void StaticClientStreaming(NanopbServerReader<FakePb, FakePb>&) {}
74*61c4878aSAndroid Build Coastguard Worker 
ClientStreamingBadReturn(NanopbServerReader<FakePb,FakePb> &)75*61c4878aSAndroid Build Coastguard Worker   int ClientStreamingBadReturn(NanopbServerReader<FakePb, FakePb>&) {
76*61c4878aSAndroid Build Coastguard Worker     return 0;
77*61c4878aSAndroid Build Coastguard Worker   }
78*61c4878aSAndroid Build Coastguard Worker 
StaticClientStreamingMissingArg()79*61c4878aSAndroid Build Coastguard Worker   static void StaticClientStreamingMissingArg() {}
80*61c4878aSAndroid Build Coastguard Worker 
81*61c4878aSAndroid Build Coastguard Worker   // Bidirectional streaming signatures
82*61c4878aSAndroid Build Coastguard Worker 
BidirectionalStreaming(NanopbServerReaderWriter<FakePb,FakePb> &)83*61c4878aSAndroid Build Coastguard Worker   void BidirectionalStreaming(NanopbServerReaderWriter<FakePb, FakePb>&) {}
84*61c4878aSAndroid Build Coastguard Worker 
StaticBidirectionalStreaming(NanopbServerReaderWriter<FakePb,FakePb> &)85*61c4878aSAndroid Build Coastguard Worker   static void StaticBidirectionalStreaming(
86*61c4878aSAndroid Build Coastguard Worker       NanopbServerReaderWriter<FakePb, FakePb>&) {}
87*61c4878aSAndroid Build Coastguard Worker 
BidirectionalStreamingBadReturn(NanopbServerReaderWriter<FakePb,FakePb> &)88*61c4878aSAndroid Build Coastguard Worker   int BidirectionalStreamingBadReturn(
89*61c4878aSAndroid Build Coastguard Worker       NanopbServerReaderWriter<FakePb, FakePb>&) {
90*61c4878aSAndroid Build Coastguard Worker     return 0;
91*61c4878aSAndroid Build Coastguard Worker   }
92*61c4878aSAndroid Build Coastguard Worker 
StaticBidirectionalStreamingMissingArg()93*61c4878aSAndroid Build Coastguard Worker   static void StaticBidirectionalStreamingMissingArg() {}
94*61c4878aSAndroid Build Coastguard Worker };
95*61c4878aSAndroid Build Coastguard Worker 
96*61c4878aSAndroid Build Coastguard Worker struct WrongPb;
97*61c4878aSAndroid Build Coastguard Worker 
98*61c4878aSAndroid Build Coastguard Worker // Test matches() rejects incorrect request/response types.
99*61c4878aSAndroid Build Coastguard Worker // clang-format off
100*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::Unary, WrongPb, FakePb>());
101*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::Unary, FakePb, WrongPb>());
102*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::Unary, WrongPb, WrongPb>());
103*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::StaticUnary, FakePb, WrongPb>());
104*61c4878aSAndroid Build Coastguard Worker 
105*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::ServerStreaming, WrongPb, FakePb>());
106*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::StaticServerStreaming, FakePb, WrongPb>());
107*61c4878aSAndroid Build Coastguard Worker 
108*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::ClientStreaming, WrongPb, FakePb>());
109*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::StaticClientStreaming, FakePb, WrongPb>());
110*61c4878aSAndroid Build Coastguard Worker 
111*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::BidirectionalStreaming, WrongPb, FakePb>());
112*61c4878aSAndroid Build Coastguard Worker static_assert(!NanopbMethod::template matches<&TestNanopbService::StaticBidirectionalStreaming, FakePb, WrongPb>());
113*61c4878aSAndroid Build Coastguard Worker // clang-format on
114*61c4878aSAndroid Build Coastguard Worker 
115*61c4878aSAndroid Build Coastguard Worker static_assert(MethodImplTests<NanopbMethod, TestNanopbService>().Pass(
116*61c4878aSAndroid Build Coastguard Worker     MatchesTypes<FakePb, FakePb>(),
117*61c4878aSAndroid Build Coastguard Worker     std::tuple<const NanopbMethodSerde&>(
118*61c4878aSAndroid Build Coastguard Worker         kNanopbMethodSerde<nullptr, nullptr>)));
119*61c4878aSAndroid Build Coastguard Worker 
120*61c4878aSAndroid Build Coastguard Worker template <typename Impl>
121*61c4878aSAndroid Build Coastguard Worker class FakeServiceBase : public Service {
122*61c4878aSAndroid Build Coastguard Worker  public:
FakeServiceBase(uint32_t id)123*61c4878aSAndroid Build Coastguard Worker   FakeServiceBase(uint32_t id) : Service(id, kMethods) {}
124*61c4878aSAndroid Build Coastguard Worker 
125*61c4878aSAndroid Build Coastguard Worker   static constexpr std::array<NanopbMethodUnion, 5> kMethods = {
126*61c4878aSAndroid Build Coastguard Worker       NanopbMethod::SynchronousUnary<&Impl::DoNothing>(
127*61c4878aSAndroid Build Coastguard Worker           10u,
128*61c4878aSAndroid Build Coastguard Worker           kNanopbMethodSerde<pw_rpc_test_Empty_fields,
129*61c4878aSAndroid Build Coastguard Worker                              pw_rpc_test_Empty_fields>),
130*61c4878aSAndroid Build Coastguard Worker       NanopbMethod::AsynchronousUnary<&Impl::AddFive>(
131*61c4878aSAndroid Build Coastguard Worker           11u,
132*61c4878aSAndroid Build Coastguard Worker           kNanopbMethodSerde<pw_rpc_test_TestRequest_fields,
133*61c4878aSAndroid Build Coastguard Worker                              pw_rpc_test_TestResponse_fields>),
134*61c4878aSAndroid Build Coastguard Worker       NanopbMethod::ServerStreaming<&Impl::StartStream>(
135*61c4878aSAndroid Build Coastguard Worker           12u,
136*61c4878aSAndroid Build Coastguard Worker           kNanopbMethodSerde<pw_rpc_test_TestRequest_fields,
137*61c4878aSAndroid Build Coastguard Worker                              pw_rpc_test_TestResponse_fields>),
138*61c4878aSAndroid Build Coastguard Worker       NanopbMethod::ClientStreaming<&Impl::ClientStream>(
139*61c4878aSAndroid Build Coastguard Worker           13u,
140*61c4878aSAndroid Build Coastguard Worker           kNanopbMethodSerde<pw_rpc_test_TestRequest_fields,
141*61c4878aSAndroid Build Coastguard Worker                              pw_rpc_test_TestResponse_fields>),
142*61c4878aSAndroid Build Coastguard Worker       NanopbMethod::BidirectionalStreaming<&Impl::BidirectionalStream>(
143*61c4878aSAndroid Build Coastguard Worker           14u,
144*61c4878aSAndroid Build Coastguard Worker           kNanopbMethodSerde<pw_rpc_test_TestRequest_fields,
145*61c4878aSAndroid Build Coastguard Worker                              pw_rpc_test_TestResponse_fields>)};
146*61c4878aSAndroid Build Coastguard Worker };
147*61c4878aSAndroid Build Coastguard Worker 
148*61c4878aSAndroid Build Coastguard Worker class FakeService : public FakeServiceBase<FakeService> {
149*61c4878aSAndroid Build Coastguard Worker  public:
FakeService(uint32_t id)150*61c4878aSAndroid Build Coastguard Worker   FakeService(uint32_t id) : FakeServiceBase(id) {}
151*61c4878aSAndroid Build Coastguard Worker 
DoNothing(const pw_rpc_test_Empty &,pw_rpc_test_Empty &)152*61c4878aSAndroid Build Coastguard Worker   Status DoNothing(const pw_rpc_test_Empty&, pw_rpc_test_Empty&) {
153*61c4878aSAndroid Build Coastguard Worker     return Status::Unknown();
154*61c4878aSAndroid Build Coastguard Worker   }
155*61c4878aSAndroid Build Coastguard Worker 
AddFive(const pw_rpc_test_TestRequest & request,NanopbUnaryResponder<pw_rpc_test_TestResponse> & responder)156*61c4878aSAndroid Build Coastguard Worker   void AddFive(const pw_rpc_test_TestRequest& request,
157*61c4878aSAndroid Build Coastguard Worker                NanopbUnaryResponder<pw_rpc_test_TestResponse>& responder) {
158*61c4878aSAndroid Build Coastguard Worker     last_request = request;
159*61c4878aSAndroid Build Coastguard Worker 
160*61c4878aSAndroid Build Coastguard Worker     if (fail_to_encode_async_unary_response) {
161*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestResponse response = pw_rpc_test_TestResponse_init_default;
162*61c4878aSAndroid Build Coastguard Worker       response.repeated_field.funcs.encode =
163*61c4878aSAndroid Build Coastguard Worker           [](pb_ostream_t*, const pb_field_t*, void* const*) { return false; };
164*61c4878aSAndroid Build Coastguard Worker       ASSERT_EQ(OkStatus(), responder.Finish(response, Status::NotFound()));
165*61c4878aSAndroid Build Coastguard Worker     } else {
166*61c4878aSAndroid Build Coastguard Worker       ASSERT_EQ(
167*61c4878aSAndroid Build Coastguard Worker           OkStatus(),
168*61c4878aSAndroid Build Coastguard Worker           responder.Finish({.value = static_cast<int32_t>(request.integer + 5)},
169*61c4878aSAndroid Build Coastguard Worker                            Status::Unauthenticated()));
170*61c4878aSAndroid Build Coastguard Worker     }
171*61c4878aSAndroid Build Coastguard Worker   }
172*61c4878aSAndroid Build Coastguard Worker 
StartStream(const pw_rpc_test_TestRequest & request,NanopbServerWriter<pw_rpc_test_TestResponse> & writer)173*61c4878aSAndroid Build Coastguard Worker   void StartStream(const pw_rpc_test_TestRequest& request,
174*61c4878aSAndroid Build Coastguard Worker                    NanopbServerWriter<pw_rpc_test_TestResponse>& writer) {
175*61c4878aSAndroid Build Coastguard Worker     last_request = request;
176*61c4878aSAndroid Build Coastguard Worker     last_writer = std::move(writer);
177*61c4878aSAndroid Build Coastguard Worker   }
178*61c4878aSAndroid Build Coastguard Worker 
ClientStream(NanopbServerReader<pw_rpc_test_TestRequest,pw_rpc_test_TestResponse> & reader)179*61c4878aSAndroid Build Coastguard Worker   void ClientStream(NanopbServerReader<pw_rpc_test_TestRequest,
180*61c4878aSAndroid Build Coastguard Worker                                        pw_rpc_test_TestResponse>& reader) {
181*61c4878aSAndroid Build Coastguard Worker     last_reader = std::move(reader);
182*61c4878aSAndroid Build Coastguard Worker   }
183*61c4878aSAndroid Build Coastguard Worker 
BidirectionalStream(NanopbServerReaderWriter<pw_rpc_test_TestRequest,pw_rpc_test_TestResponse> & reader_writer)184*61c4878aSAndroid Build Coastguard Worker   void BidirectionalStream(
185*61c4878aSAndroid Build Coastguard Worker       NanopbServerReaderWriter<pw_rpc_test_TestRequest,
186*61c4878aSAndroid Build Coastguard Worker                                pw_rpc_test_TestResponse>& reader_writer) {
187*61c4878aSAndroid Build Coastguard Worker     last_reader_writer = std::move(reader_writer);
188*61c4878aSAndroid Build Coastguard Worker   }
189*61c4878aSAndroid Build Coastguard Worker 
190*61c4878aSAndroid Build Coastguard Worker   bool fail_to_encode_async_unary_response = false;
191*61c4878aSAndroid Build Coastguard Worker 
192*61c4878aSAndroid Build Coastguard Worker   pw_rpc_test_TestRequest last_request;
193*61c4878aSAndroid Build Coastguard Worker   NanopbServerWriter<pw_rpc_test_TestResponse> last_writer;
194*61c4878aSAndroid Build Coastguard Worker   NanopbServerReader<pw_rpc_test_TestRequest, pw_rpc_test_TestResponse>
195*61c4878aSAndroid Build Coastguard Worker       last_reader;
196*61c4878aSAndroid Build Coastguard Worker   NanopbServerReaderWriter<pw_rpc_test_TestRequest, pw_rpc_test_TestResponse>
197*61c4878aSAndroid Build Coastguard Worker       last_reader_writer;
198*61c4878aSAndroid Build Coastguard Worker };
199*61c4878aSAndroid Build Coastguard Worker 
200*61c4878aSAndroid Build Coastguard Worker constexpr const NanopbMethod& kSyncUnary =
201*61c4878aSAndroid Build Coastguard Worker     std::get<0>(FakeServiceBase<FakeService>::kMethods).nanopb_method();
202*61c4878aSAndroid Build Coastguard Worker constexpr const NanopbMethod& kAsyncUnary =
203*61c4878aSAndroid Build Coastguard Worker     std::get<1>(FakeServiceBase<FakeService>::kMethods).nanopb_method();
204*61c4878aSAndroid Build Coastguard Worker constexpr const NanopbMethod& kServerStream =
205*61c4878aSAndroid Build Coastguard Worker     std::get<2>(FakeServiceBase<FakeService>::kMethods).nanopb_method();
206*61c4878aSAndroid Build Coastguard Worker constexpr const NanopbMethod& kClientStream =
207*61c4878aSAndroid Build Coastguard Worker     std::get<3>(FakeServiceBase<FakeService>::kMethods).nanopb_method();
208*61c4878aSAndroid Build Coastguard Worker constexpr const NanopbMethod& kBidirectionalStream =
209*61c4878aSAndroid Build Coastguard Worker     std::get<4>(FakeServiceBase<FakeService>::kMethods).nanopb_method();
210*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,AsyncUnaryRpc_SendsResponse)211*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, AsyncUnaryRpc_SendsResponse) {
212*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(
213*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestRequest, request, .integer = 123, .status_code = 0);
214*61c4878aSAndroid Build Coastguard Worker 
215*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kAsyncUnary);
216*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
217*61c4878aSAndroid Build Coastguard Worker   kAsyncUnary.Invoke(context.get(), context.request(request));
218*61c4878aSAndroid Build Coastguard Worker 
219*61c4878aSAndroid Build Coastguard Worker   const Packet& response = context.output().last_packet();
220*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.status(), Status::Unauthenticated());
221*61c4878aSAndroid Build Coastguard Worker 
222*61c4878aSAndroid Build Coastguard Worker   // Field 1 (encoded as 1 << 3) with 128 as the value.
223*61c4878aSAndroid Build Coastguard Worker   constexpr std::byte expected[]{
224*61c4878aSAndroid Build Coastguard Worker       std::byte{0x08}, std::byte{0x80}, std::byte{0x01}};
225*61c4878aSAndroid Build Coastguard Worker 
226*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(sizeof(expected), response.payload().size());
227*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0,
228*61c4878aSAndroid Build Coastguard Worker             std::memcmp(expected, response.payload().data(), sizeof(expected)));
229*61c4878aSAndroid Build Coastguard Worker 
230*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(123, context.service().last_request.integer);
231*61c4878aSAndroid Build Coastguard Worker }
232*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,SyncUnaryRpc_InvalidPayload_SendsError)233*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, SyncUnaryRpc_InvalidPayload_SendsError) {
234*61c4878aSAndroid Build Coastguard Worker   std::array<byte, 8> bad_payload{byte{0xFF}, byte{0xAA}, byte{0xDD}};
235*61c4878aSAndroid Build Coastguard Worker 
236*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kSyncUnary);
237*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
238*61c4878aSAndroid Build Coastguard Worker   kSyncUnary.Invoke(context.get(), context.request(bad_payload));
239*61c4878aSAndroid Build Coastguard Worker 
240*61c4878aSAndroid Build Coastguard Worker   const Packet& packet = context.output().last_packet();
241*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(pwpb::PacketType::SERVER_ERROR, packet.type());
242*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::DataLoss(), packet.status());
243*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(context.service_id(), packet.service_id());
244*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kSyncUnary.id(), packet.method_id());
245*61c4878aSAndroid Build Coastguard Worker }
246*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,AsyncUnaryRpc_ResponseEncodingFails_SendsInternalError)247*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, AsyncUnaryRpc_ResponseEncodingFails_SendsInternalError) {
248*61c4878aSAndroid Build Coastguard Worker   constexpr int64_t value = 0x7FFFFFFF'FFFFFF00ll;
249*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(
250*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestRequest, request, .integer = value, .status_code = 0);
251*61c4878aSAndroid Build Coastguard Worker 
252*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kAsyncUnary);
253*61c4878aSAndroid Build Coastguard Worker   context.service().fail_to_encode_async_unary_response = true;
254*61c4878aSAndroid Build Coastguard Worker 
255*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
256*61c4878aSAndroid Build Coastguard Worker   kAsyncUnary.Invoke(context.get(), context.request(request));
257*61c4878aSAndroid Build Coastguard Worker 
258*61c4878aSAndroid Build Coastguard Worker   const Packet& packet = context.output().last_packet();
259*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(pwpb::PacketType::SERVER_ERROR, packet.type());
260*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::Internal(), packet.status());
261*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(context.service_id(), packet.service_id());
262*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(kAsyncUnary.id(), packet.method_id());
263*61c4878aSAndroid Build Coastguard Worker 
264*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(value, context.service().last_request.integer);
265*61c4878aSAndroid Build Coastguard Worker }
266*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerStreamingRpc_SendsNothingWhenInitiallyCalled)267*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerStreamingRpc_SendsNothingWhenInitiallyCalled) {
268*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(
269*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestRequest, request, .integer = 555, .status_code = 0);
270*61c4878aSAndroid Build Coastguard Worker 
271*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kServerStream);
272*61c4878aSAndroid Build Coastguard Worker 
273*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
274*61c4878aSAndroid Build Coastguard Worker   kServerStream.Invoke(context.get(), context.request(request));
275*61c4878aSAndroid Build Coastguard Worker 
276*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(0u, context.output().total_packets());
277*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(555, context.service().last_request.integer);
278*61c4878aSAndroid Build Coastguard Worker }
279*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerWriter_SendsResponse)280*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerWriter_SendsResponse) {
281*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kServerStream);
282*61c4878aSAndroid Build Coastguard Worker 
283*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
284*61c4878aSAndroid Build Coastguard Worker   kServerStream.Invoke(context.get(), context.request({}));
285*61c4878aSAndroid Build Coastguard Worker 
286*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), context.service().last_writer.Write({.value = 100}));
287*61c4878aSAndroid Build Coastguard Worker 
288*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(pw_rpc_test_TestResponse, payload, .value = 100);
289*61c4878aSAndroid Build Coastguard Worker   std::array<byte, 128> encoded_response = {};
290*61c4878aSAndroid Build Coastguard Worker   auto encoded = context.server_stream(payload).Encode(encoded_response);
291*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), encoded.status());
292*61c4878aSAndroid Build Coastguard Worker 
293*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan sent_payload = context.output().last_packet().payload();
294*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::containers::Equal(payload, sent_payload));
295*61c4878aSAndroid Build Coastguard Worker }
296*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerWriter_WriteWhenClosed_ReturnsFailedPrecondition)297*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerWriter_WriteWhenClosed_ReturnsFailedPrecondition) {
298*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kServerStream);
299*61c4878aSAndroid Build Coastguard Worker 
300*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
301*61c4878aSAndroid Build Coastguard Worker   kServerStream.Invoke(context.get(), context.request({}));
302*61c4878aSAndroid Build Coastguard Worker 
303*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), context.service().last_writer.Finish());
304*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(context.service()
305*61c4878aSAndroid Build Coastguard Worker                   .last_writer.Write({.value = 100})
306*61c4878aSAndroid Build Coastguard Worker                   .IsFailedPrecondition());
307*61c4878aSAndroid Build Coastguard Worker }
308*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerWriter_WriteAfterMoved_ReturnsFailedPrecondition)309*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerWriter_WriteAfterMoved_ReturnsFailedPrecondition) {
310*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kServerStream);
311*61c4878aSAndroid Build Coastguard Worker 
312*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
313*61c4878aSAndroid Build Coastguard Worker   kServerStream.Invoke(context.get(), context.request({}));
314*61c4878aSAndroid Build Coastguard Worker   NanopbServerWriter<pw_rpc_test_TestResponse> new_writer =
315*61c4878aSAndroid Build Coastguard Worker       std::move(context.service().last_writer);
316*61c4878aSAndroid Build Coastguard Worker 
317*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), new_writer.Write({.value = 100}));
318*61c4878aSAndroid Build Coastguard Worker 
319*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::FailedPrecondition(),
320*61c4878aSAndroid Build Coastguard Worker             context.service().last_writer.Write({.value = 100}));
321*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::FailedPrecondition(),
322*61c4878aSAndroid Build Coastguard Worker             context.service().last_writer.Finish());
323*61c4878aSAndroid Build Coastguard Worker 
324*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), new_writer.Finish());
325*61c4878aSAndroid Build Coastguard Worker }
326*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerStreamingRpc_ResponseEncodingFails_InternalError)327*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerStreamingRpc_ResponseEncodingFails_InternalError) {
328*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kServerStream);
329*61c4878aSAndroid Build Coastguard Worker 
330*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
331*61c4878aSAndroid Build Coastguard Worker   kServerStream.Invoke(context.get(), context.request({}));
332*61c4878aSAndroid Build Coastguard Worker 
333*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(), context.service().last_writer.Write({}));
334*61c4878aSAndroid Build Coastguard Worker 
335*61c4878aSAndroid Build Coastguard Worker   pw_rpc_test_TestResponse response = pw_rpc_test_TestResponse_init_default;
336*61c4878aSAndroid Build Coastguard Worker   response.repeated_field.funcs.encode =
337*61c4878aSAndroid Build Coastguard Worker       [](pb_ostream_t*, const pb_field_t*, void* const*) { return false; };
338*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Status::Internal(), context.service().last_writer.Write(response));
339*61c4878aSAndroid Build Coastguard Worker }
340*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerReader_HandlesRequests)341*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerReader_HandlesRequests) {
342*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kClientStream);
343*61c4878aSAndroid Build Coastguard Worker 
344*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
345*61c4878aSAndroid Build Coastguard Worker   kClientStream.Invoke(context.get(), context.request({}));
346*61c4878aSAndroid Build Coastguard Worker 
347*61c4878aSAndroid Build Coastguard Worker   pw_rpc_test_TestRequest request_struct{};
348*61c4878aSAndroid Build Coastguard Worker   context.service().last_reader.set_on_next(
349*61c4878aSAndroid Build Coastguard Worker       [&request_struct](const pw_rpc_test_TestRequest& req) {
350*61c4878aSAndroid Build Coastguard Worker         request_struct = req;
351*61c4878aSAndroid Build Coastguard Worker       });
352*61c4878aSAndroid Build Coastguard Worker 
353*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(
354*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestRequest, request, .integer = 1 << 30, .status_code = 9);
355*61c4878aSAndroid Build Coastguard Worker   std::array<byte, 128> encoded_request = {};
356*61c4878aSAndroid Build Coastguard Worker   auto encoded = context.client_stream(request).Encode(encoded_request);
357*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), encoded.status());
358*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), context.server().ProcessPacket(*encoded));
359*61c4878aSAndroid Build Coastguard Worker 
360*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(request_struct.integer, 1 << 30);
361*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(request_struct.status_code, 9u);
362*61c4878aSAndroid Build Coastguard Worker }
363*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerReaderWriter_WritesResponses)364*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerReaderWriter_WritesResponses) {
365*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kBidirectionalStream);
366*61c4878aSAndroid Build Coastguard Worker 
367*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
368*61c4878aSAndroid Build Coastguard Worker   kBidirectionalStream.Invoke(context.get(), context.request({}));
369*61c4878aSAndroid Build Coastguard Worker 
370*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(OkStatus(),
371*61c4878aSAndroid Build Coastguard Worker             context.service().last_reader_writer.Write({.value = 100}));
372*61c4878aSAndroid Build Coastguard Worker 
373*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(pw_rpc_test_TestResponse, payload, .value = 100);
374*61c4878aSAndroid Build Coastguard Worker   std::array<byte, 128> encoded_response = {};
375*61c4878aSAndroid Build Coastguard Worker   auto encoded = context.server_stream(payload).Encode(encoded_response);
376*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), encoded.status());
377*61c4878aSAndroid Build Coastguard Worker 
378*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan sent_payload = context.output().last_packet().payload();
379*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::containers::Equal(payload, sent_payload));
380*61c4878aSAndroid Build Coastguard Worker }
381*61c4878aSAndroid Build Coastguard Worker 
TEST(NanopbMethod,ServerReaderWriter_HandlesRequests)382*61c4878aSAndroid Build Coastguard Worker TEST(NanopbMethod, ServerReaderWriter_HandlesRequests) {
383*61c4878aSAndroid Build Coastguard Worker   ServerContextForTest<FakeService> context(kBidirectionalStream);
384*61c4878aSAndroid Build Coastguard Worker 
385*61c4878aSAndroid Build Coastguard Worker   rpc_lock().lock();
386*61c4878aSAndroid Build Coastguard Worker   kBidirectionalStream.Invoke(context.get(), context.request({}));
387*61c4878aSAndroid Build Coastguard Worker 
388*61c4878aSAndroid Build Coastguard Worker   pw_rpc_test_TestRequest request_struct{};
389*61c4878aSAndroid Build Coastguard Worker   context.service().last_reader_writer.set_on_next(
390*61c4878aSAndroid Build Coastguard Worker       [&request_struct](const pw_rpc_test_TestRequest& req) {
391*61c4878aSAndroid Build Coastguard Worker         request_struct = req;
392*61c4878aSAndroid Build Coastguard Worker       });
393*61c4878aSAndroid Build Coastguard Worker 
394*61c4878aSAndroid Build Coastguard Worker   PW_ENCODE_PB(
395*61c4878aSAndroid Build Coastguard Worker       pw_rpc_test_TestRequest, request, .integer = 1 << 29, .status_code = 8);
396*61c4878aSAndroid Build Coastguard Worker   std::array<byte, 128> encoded_request = {};
397*61c4878aSAndroid Build Coastguard Worker   auto encoded = context.client_stream(request).Encode(encoded_request);
398*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), encoded.status());
399*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), context.server().ProcessPacket(*encoded));
400*61c4878aSAndroid Build Coastguard Worker 
401*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(request_struct.integer, 1 << 29);
402*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(request_struct.status_code, 8u);
403*61c4878aSAndroid Build Coastguard Worker }
404*61c4878aSAndroid Build Coastguard Worker 
405*61c4878aSAndroid Build Coastguard Worker }  // namespace
406*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::rpc::internal
407*61c4878aSAndroid Build Coastguard Worker 
408*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTICS_POP();
409