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