xref: /aosp_15_r20/external/pigweed/pw_rpc/pwpb/codegen_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_preprocessor/compiler.h"
16 #include "pw_rpc/internal/hash.h"
17 #include "pw_rpc/internal/test_utils.h"
18 #include "pw_rpc/pwpb/test_method_context.h"
19 #include "pw_rpc_pwpb_private/internal_test_utils.h"
20 #include "pw_rpc_test_protos/test.rpc.pwpb.h"
21 #include "pw_unit_test/framework.h"
22 
23 PW_MODIFY_DIAGNOSTICS_PUSH();
24 PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers");
25 
26 namespace pw::rpc {
27 namespace test {
28 
29 class TestService final
30     : public pw_rpc::pwpb::TestService::Service<TestService> {
31  public:
TestUnaryRpc(const pwpb::TestRequest::Message & request,pwpb::TestResponse::Message & response)32   Status TestUnaryRpc(const pwpb::TestRequest::Message& request,
33                       pwpb::TestResponse::Message& response) {
34     response.value = request.integer + 1;
35     return static_cast<Status::Code>(request.status_code);
36   }
37 
TestAnotherUnaryRpc(const pwpb::TestRequest::Message & request,PwpbUnaryResponder<pwpb::TestResponse::Message> & responder)38   void TestAnotherUnaryRpc(
39       const pwpb::TestRequest::Message& request,
40       PwpbUnaryResponder<pwpb::TestResponse::Message>& responder) {
41     pwpb::TestResponse::Message response{};
42     EXPECT_EQ(OkStatus(),
43               responder.Finish(response, TestUnaryRpc(request, response)));
44   }
45 
TestServerStreamRpc(const pwpb::TestRequest::Message & request,ServerWriter<pwpb::TestStreamResponse::Message> & writer)46   static void TestServerStreamRpc(
47       const pwpb::TestRequest::Message& request,
48       ServerWriter<pwpb::TestStreamResponse::Message>& writer) {
49     for (int i = 0; i < request.integer; ++i) {
50       EXPECT_EQ(
51           OkStatus(),
52           writer.Write({.chunk = {}, .number = static_cast<uint32_t>(i)}));
53     }
54 
55     EXPECT_EQ(OkStatus(),
56               writer.Finish(static_cast<Status::Code>(request.status_code)));
57   }
58 
TestClientStreamRpc(ServerReader<pwpb::TestRequest::Message,pwpb::TestStreamResponse::Message> & new_reader)59   void TestClientStreamRpc(
60       ServerReader<pwpb::TestRequest::Message,
61                    pwpb::TestStreamResponse::Message>& new_reader) {
62     reader = std::move(new_reader);
63   }
64 
TestBidirectionalStreamRpc(ServerReaderWriter<pwpb::TestRequest::Message,pwpb::TestStreamResponse::Message> & new_reader_writer)65   void TestBidirectionalStreamRpc(
66       ServerReaderWriter<pwpb::TestRequest::Message,
67                          pwpb::TestStreamResponse::Message>&
68           new_reader_writer) {
69     reader_writer = std::move(new_reader_writer);
70   }
71 
72   ServerReader<pwpb::TestRequest::Message, pwpb::TestStreamResponse::Message>
73       reader;
74   ServerReaderWriter<pwpb::TestRequest::Message,
75                      pwpb::TestStreamResponse::Message>
76       reader_writer;
77 };
78 
79 }  // namespace test
80 
81 namespace {
82 
83 using internal::ClientContextForTest;
84 
TEST(PwpbCodegen,CompilesProperly)85 TEST(PwpbCodegen, CompilesProperly) {
86   test::TestService service;
87   EXPECT_EQ(internal::UnwrapServiceId(service.service_id()),
88             internal::Hash("pw.rpc.test.TestService"));
89   EXPECT_STREQ(service.name(), "TestService");
90 }
91 
TEST(PwpbCodegen,Server_InvokeUnaryRpc)92 TEST(PwpbCodegen, Server_InvokeUnaryRpc) {
93   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestUnaryRpc) context;
94 
95   EXPECT_EQ(OkStatus(),
96             context.call({.integer = 123, .status_code = OkStatus().code()}));
97 
98   EXPECT_EQ(124, context.response().value);
99 
100   EXPECT_EQ(Status::InvalidArgument(),
101             context.call({.integer = 999,
102                           .status_code = Status::InvalidArgument().code()}));
103   EXPECT_EQ(1000, context.response().value);
104 }
105 
TEST(PwpbCodegen,Server_InvokeAsyncUnaryRpc)106 TEST(PwpbCodegen, Server_InvokeAsyncUnaryRpc) {
107   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestAnotherUnaryRpc) context;
108 
109   context.call({.integer = 123, .status_code = OkStatus().code()});
110 
111   EXPECT_EQ(OkStatus(), context.status());
112   EXPECT_EQ(124, context.response().value);
113 
114   context.call(
115       {.integer = 999, .status_code = Status::InvalidArgument().code()});
116   EXPECT_EQ(Status::InvalidArgument(), context.status());
117   EXPECT_EQ(1000, context.response().value);
118 }
119 
TEST(PwpbCodegen,Server_InvokeServerStreamingRpc)120 TEST(PwpbCodegen, Server_InvokeServerStreamingRpc) {
121   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestServerStreamRpc) context;
122 
123   context.call({.integer = 0, .status_code = Status::Aborted().code()});
124 
125   EXPECT_EQ(Status::Aborted(), context.status());
126   EXPECT_TRUE(context.done());
127   EXPECT_EQ(context.total_responses(), 0u);
128 
129   context.call({.integer = 4, .status_code = OkStatus().code()});
130 
131   ASSERT_EQ(4u, context.responses().size());
132 
133   for (size_t i = 0; i < context.responses().size(); ++i) {
134     EXPECT_EQ(context.responses()[i].number, i);
135   }
136 
137   EXPECT_EQ(OkStatus().code(), context.status());
138 }
139 
TEST(PwpbCodegen,Server_InvokeServerStreamingRpc_ManualWriting)140 TEST(PwpbCodegen, Server_InvokeServerStreamingRpc_ManualWriting) {
141   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestServerStreamRpc, 4)
142   context;
143 
144   ASSERT_EQ(4u, context.max_packets());
145 
146   auto writer = context.writer();
147 
148   EXPECT_EQ(OkStatus(), writer.Write({.chunk = {}, .number = 3}));
149   EXPECT_EQ(OkStatus(), writer.Write({.chunk = {}, .number = 6}));
150   EXPECT_EQ(OkStatus(), writer.Write({.chunk = {}, .number = 9}));
151 
152   EXPECT_FALSE(context.done());
153 
154   EXPECT_EQ(OkStatus(), writer.Finish(Status::Cancelled()));
155   ASSERT_TRUE(context.done());
156   EXPECT_EQ(Status::Cancelled(), context.status());
157 
158   ASSERT_EQ(3u, context.responses().size());
159 
160   EXPECT_EQ(context.responses()[0].number, 3u);
161   EXPECT_EQ(context.responses()[1].number, 6u);
162   EXPECT_EQ(context.responses()[2].number, 9u);
163 }
164 
TEST(PwpbCodegen,Server_InvokeClientStreamingRpc)165 TEST(PwpbCodegen, Server_InvokeClientStreamingRpc) {
166   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestClientStreamRpc) context;
167 
168   context.call();
169 
170   test::pwpb::TestRequest::Message request = {};
171   context.service().reader.set_on_next(
172       [&request](const test::pwpb::TestRequest::Message& req) {
173         request = req;
174       });
175 
176   context.SendClientStream({.integer = -99, .status_code = 10});
177   EXPECT_EQ(request.integer, -99);
178   EXPECT_EQ(request.status_code, 10u);
179 
180   ASSERT_EQ(OkStatus(),
181             context.service().reader.Finish({.chunk = {}, .number = 3},
182                                             Status::Unimplemented()));
183   EXPECT_EQ(Status::Unimplemented(), context.status());
184   EXPECT_EQ(context.response().number, 3u);
185 }
186 
TEST(PwpbCodegen,Server_InvokeBidirectionalStreamingRpc)187 TEST(PwpbCodegen, Server_InvokeBidirectionalStreamingRpc) {
188   PW_PWPB_TEST_METHOD_CONTEXT(test::TestService, TestBidirectionalStreamRpc)
189   context;
190 
191   context.call();
192 
193   test::pwpb::TestRequest::Message request = {};
194   context.service().reader_writer.set_on_next(
195       [&request](const test::pwpb::TestRequest::Message& req) {
196         request = req;
197       });
198 
199   context.SendClientStream({.integer = -99, .status_code = 10});
200   EXPECT_EQ(request.integer, -99);
201   EXPECT_EQ(request.status_code, 10u);
202 
203   ASSERT_EQ(OkStatus(),
204             context.service().reader_writer.Write({.chunk = {}, .number = 2}));
205   EXPECT_EQ(context.responses()[0].number, 2u);
206 
207   ASSERT_EQ(OkStatus(),
208             context.service().reader_writer.Finish(Status::NotFound()));
209   EXPECT_EQ(Status::NotFound(), context.status());
210 }
211 
TEST(PwpbCodegen,ClientCall_DefaultConstructor)212 TEST(PwpbCodegen, ClientCall_DefaultConstructor) {
213   PwpbUnaryReceiver<test::pwpb::TestResponse::Message> unary_call;
214   PwpbClientReader<test::pwpb::TestStreamResponse::Message>
215       server_streaming_call;
216 }
217 
218 using TestServiceClient = test::pw_rpc::pwpb::TestService::Client;
219 
TEST(PwpbCodegen,Client_InvokesUnaryRpcWithCallback)220 TEST(PwpbCodegen, Client_InvokesUnaryRpcWithCallback) {
221   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
222   constexpr uint32_t kMethodId = internal::Hash("TestUnaryRpc");
223 
224   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
225 
226   TestServiceClient test_client(context.client(), context.channel().id());
227 
228   struct {
229     Status last_status = Status::Unknown();
230     int response_value = -1;
231   } result;
232 
233   auto call = test_client.TestUnaryRpc(
234       {.integer = 123, .status_code = 0},
235       [&result](const test::pwpb::TestResponse::Message& response,
236                 Status status) {
237         result.last_status = status;
238         result.response_value = response.value;
239       });
240 
241   EXPECT_TRUE(call.active());
242 
243   EXPECT_EQ(context.output().total_packets(), 1u);
244   auto packet =
245       static_cast<const internal::test::FakeChannelOutput&>(context.output())
246           .last_packet();
247   EXPECT_EQ(packet.channel_id(), context.channel().id());
248   EXPECT_EQ(packet.service_id(), kServiceId);
249   EXPECT_EQ(packet.method_id(), kMethodId);
250   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
251   EXPECT_EQ(sent_proto.integer, 123);
252 
253   PW_ENCODE_PB(test::pwpb::TestResponse, response, .value = 42);
254   EXPECT_EQ(OkStatus(), context.SendResponse(OkStatus(), response));
255   EXPECT_EQ(result.last_status, OkStatus());
256   EXPECT_EQ(result.response_value, 42);
257 
258   EXPECT_FALSE(call.active());
259 }
260 
261 #if PW_RPC_DYNAMIC_ALLOCATION
262 
TEST(PwpbCodegen,DynamicClient_InvokesUnaryRpcWithCallback)263 TEST(PwpbCodegen, DynamicClient_InvokesUnaryRpcWithCallback) {
264   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
265   constexpr uint32_t kMethodId = internal::Hash("TestUnaryRpc");
266 
267   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
268 
269   test::pw_rpc::pwpb::TestService::DynamicClient test_client(
270       context.client(), context.channel().id());
271 
272   struct {
273     Status last_status = Status::Unknown();
274     int response_value = -1;
275   } result;
276 
277   auto call = test_client.TestUnaryRpc(
278       {.integer = 123, .status_code = 0},
279       [&result](const test::pwpb::TestResponse::Message& response,
280                 Status status) {
281         result.last_status = status;
282         result.response_value = response.value;
283       });
284 
285   EXPECT_TRUE(call->active());
286 
287   EXPECT_EQ(context.output().total_packets(), 1u);
288   auto packet =
289       static_cast<const internal::test::FakeChannelOutput&>(context.output())
290           .last_packet();
291   EXPECT_EQ(packet.channel_id(), context.channel().id());
292   EXPECT_EQ(packet.service_id(), kServiceId);
293   EXPECT_EQ(packet.method_id(), kMethodId);
294   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
295   EXPECT_EQ(sent_proto.integer, 123);
296 
297   PW_ENCODE_PB(test::pwpb::TestResponse, response, .value = 42);
298   EXPECT_EQ(OkStatus(), context.SendResponse(OkStatus(), response));
299   EXPECT_EQ(result.last_status, OkStatus());
300   EXPECT_EQ(result.response_value, 42);
301 
302   EXPECT_FALSE(call->active());
303 }
304 
305 #endif  // PW_RPC_DYNAMIC_ALLOCATION
306 
TEST(PwpbCodegen,Client_InvokesServerStreamingRpcWithCallback)307 TEST(PwpbCodegen, Client_InvokesServerStreamingRpcWithCallback) {
308   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
309   constexpr uint32_t kMethodId = internal::Hash("TestServerStreamRpc");
310 
311   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
312 
313   TestServiceClient test_client(context.client(), context.channel().id());
314 
315   struct {
316     bool active = true;
317     Status stream_status = Status::Unknown();
318     int response_value = -1;
319   } result;
320 
321   auto call = test_client.TestServerStreamRpc(
322       {.integer = 123, .status_code = 0},
323       [&result](const test::pwpb::TestStreamResponse::Message& response) {
324         result.active = true;
325         result.response_value = response.number;
326       },
327       [&result](Status status) {
328         result.active = false;
329         result.stream_status = status;
330       });
331 
332   EXPECT_TRUE(call.active());
333 
334   EXPECT_EQ(context.output().total_packets(), 1u);
335   auto packet =
336       static_cast<const internal::test::FakeChannelOutput&>(context.output())
337           .last_packet();
338   EXPECT_EQ(packet.channel_id(), context.channel().id());
339   EXPECT_EQ(packet.service_id(), kServiceId);
340   EXPECT_EQ(packet.method_id(), kMethodId);
341   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
342   EXPECT_EQ(sent_proto.integer, 123);
343 
344   PW_ENCODE_PB(
345       test::pwpb::TestStreamResponse, response, .chunk = {}, .number = 11u);
346   EXPECT_EQ(OkStatus(), context.SendServerStream(response));
347   EXPECT_TRUE(result.active);
348   EXPECT_EQ(result.response_value, 11);
349 
350   EXPECT_EQ(OkStatus(), context.SendResponse(Status::NotFound()));
351   EXPECT_FALSE(result.active);
352   EXPECT_EQ(result.stream_status, Status::NotFound());
353 }
354 
TEST(PwpbCodegen,Client_StaticMethod_InvokesUnaryRpcWithCallback)355 TEST(PwpbCodegen, Client_StaticMethod_InvokesUnaryRpcWithCallback) {
356   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
357   constexpr uint32_t kMethodId = internal::Hash("TestUnaryRpc");
358 
359   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
360 
361   struct {
362     Status last_status = Status::Unknown();
363     int response_value = -1;
364   } result;
365 
366   auto call = test::pw_rpc::pwpb::TestService::TestUnaryRpc(
367       context.client(),
368       context.channel().id(),
369       {.integer = 123, .status_code = 0},
370       [&result](const test::pwpb::TestResponse::Message& response,
371                 Status status) {
372         result.last_status = status;
373         result.response_value = response.value;
374       });
375 
376   EXPECT_TRUE(call.active());
377 
378   EXPECT_EQ(context.output().total_packets(), 1u);
379   auto packet =
380       static_cast<const internal::test::FakeChannelOutput&>(context.output())
381           .last_packet();
382   EXPECT_EQ(packet.channel_id(), context.channel().id());
383   EXPECT_EQ(packet.service_id(), kServiceId);
384   EXPECT_EQ(packet.method_id(), kMethodId);
385   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
386   EXPECT_EQ(sent_proto.integer, 123);
387 
388   PW_ENCODE_PB(test::pwpb::TestResponse, response, .value = 42);
389   EXPECT_EQ(OkStatus(), context.SendResponse(OkStatus(), response));
390   EXPECT_EQ(result.last_status, OkStatus());
391   EXPECT_EQ(result.response_value, 42);
392 }
393 
TEST(PwpbCodegen,Client_StaticMethod_InvokesServerStreamingRpcWithCallback)394 TEST(PwpbCodegen, Client_StaticMethod_InvokesServerStreamingRpcWithCallback) {
395   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
396   constexpr uint32_t kMethodId = internal::Hash("TestServerStreamRpc");
397 
398   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
399 
400   struct {
401     bool active = true;
402     Status stream_status = Status::Unknown();
403     int response_value = -1;
404   } result;
405 
406   auto call = test::pw_rpc::pwpb::TestService::TestServerStreamRpc(
407       context.client(),
408       context.channel().id(),
409       {.integer = 123, .status_code = 0},
410       [&result](const test::pwpb::TestStreamResponse::Message& response) {
411         result.active = true;
412         result.response_value = response.number;
413       },
414       [&result](Status status) {
415         result.active = false;
416         result.stream_status = status;
417       });
418 
419   EXPECT_TRUE(call.active());
420 
421   EXPECT_EQ(context.output().total_packets(), 1u);
422   auto packet =
423       static_cast<const internal::test::FakeChannelOutput&>(context.output())
424           .last_packet();
425   EXPECT_EQ(packet.channel_id(), context.channel().id());
426   EXPECT_EQ(packet.service_id(), kServiceId);
427   EXPECT_EQ(packet.method_id(), kMethodId);
428   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
429   EXPECT_EQ(sent_proto.integer, 123);
430 
431   PW_ENCODE_PB(
432       test::pwpb::TestStreamResponse, response, .chunk = {}, .number = 11u);
433   EXPECT_EQ(OkStatus(), context.SendServerStream(response));
434   EXPECT_TRUE(result.active);
435   EXPECT_EQ(result.response_value, 11);
436 
437   EXPECT_EQ(OkStatus(), context.SendResponse(Status::NotFound()));
438   EXPECT_FALSE(result.active);
439   EXPECT_EQ(result.stream_status, Status::NotFound());
440 }
441 
442 }  // namespace
443 }  // namespace pw::rpc
444 
445 PW_MODIFY_DIAGNOSTICS_POP();
446