• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
16 #include "pw_preprocessor/compiler.h"
17 #include "pw_rpc/internal/hash.h"
18 #include "pw_rpc/internal/test_utils.h"
19 #include "pw_rpc/pwpb/test_method_context.h"
20 #include "pw_rpc_pwpb_private/internal_test_utils.h"
21 #include "pw_rpc_test_protos/test.rpc.pwpb.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 
TEST(PwpbCodegen,Client_InvokesServerStreamingRpcWithCallback)261 TEST(PwpbCodegen, Client_InvokesServerStreamingRpcWithCallback) {
262   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
263   constexpr uint32_t kMethodId = internal::Hash("TestServerStreamRpc");
264 
265   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
266 
267   TestServiceClient test_client(context.client(), context.channel().id());
268 
269   struct {
270     bool active = true;
271     Status stream_status = Status::Unknown();
272     int response_value = -1;
273   } result;
274 
275   auto call = test_client.TestServerStreamRpc(
276       {.integer = 123, .status_code = 0},
277       [&result](const test::pwpb::TestStreamResponse::Message& response) {
278         result.active = true;
279         result.response_value = response.number;
280       },
281       [&result](Status status) {
282         result.active = false;
283         result.stream_status = status;
284       });
285 
286   EXPECT_TRUE(call.active());
287 
288   EXPECT_EQ(context.output().total_packets(), 1u);
289   auto packet =
290       static_cast<const internal::test::FakeChannelOutput&>(context.output())
291           .last_packet();
292   EXPECT_EQ(packet.channel_id(), context.channel().id());
293   EXPECT_EQ(packet.service_id(), kServiceId);
294   EXPECT_EQ(packet.method_id(), kMethodId);
295   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
296   EXPECT_EQ(sent_proto.integer, 123);
297 
298   PW_ENCODE_PB(
299       test::pwpb::TestStreamResponse, response, .chunk = {}, .number = 11u);
300   EXPECT_EQ(OkStatus(), context.SendServerStream(response));
301   EXPECT_TRUE(result.active);
302   EXPECT_EQ(result.response_value, 11);
303 
304   EXPECT_EQ(OkStatus(), context.SendResponse(Status::NotFound()));
305   EXPECT_FALSE(result.active);
306   EXPECT_EQ(result.stream_status, Status::NotFound());
307 }
308 
TEST(PwpbCodegen,Client_StaticMethod_InvokesUnaryRpcWithCallback)309 TEST(PwpbCodegen, Client_StaticMethod_InvokesUnaryRpcWithCallback) {
310   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
311   constexpr uint32_t kMethodId = internal::Hash("TestUnaryRpc");
312 
313   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
314 
315   struct {
316     Status last_status = Status::Unknown();
317     int response_value = -1;
318   } result;
319 
320   auto call = test::pw_rpc::pwpb::TestService::TestUnaryRpc(
321       context.client(),
322       context.channel().id(),
323       {.integer = 123, .status_code = 0},
324       [&result](const test::pwpb::TestResponse::Message& response,
325                 Status status) {
326         result.last_status = status;
327         result.response_value = response.value;
328       });
329 
330   EXPECT_TRUE(call.active());
331 
332   EXPECT_EQ(context.output().total_packets(), 1u);
333   auto packet =
334       static_cast<const internal::test::FakeChannelOutput&>(context.output())
335           .last_packet();
336   EXPECT_EQ(packet.channel_id(), context.channel().id());
337   EXPECT_EQ(packet.service_id(), kServiceId);
338   EXPECT_EQ(packet.method_id(), kMethodId);
339   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
340   EXPECT_EQ(sent_proto.integer, 123);
341 
342   PW_ENCODE_PB(test::pwpb::TestResponse, response, .value = 42);
343   EXPECT_EQ(OkStatus(), context.SendResponse(OkStatus(), response));
344   EXPECT_EQ(result.last_status, OkStatus());
345   EXPECT_EQ(result.response_value, 42);
346 }
347 
TEST(PwpbCodegen,Client_StaticMethod_InvokesServerStreamingRpcWithCallback)348 TEST(PwpbCodegen, Client_StaticMethod_InvokesServerStreamingRpcWithCallback) {
349   constexpr uint32_t kServiceId = internal::Hash("pw.rpc.test.TestService");
350   constexpr uint32_t kMethodId = internal::Hash("TestServerStreamRpc");
351 
352   ClientContextForTest<128, 99, kServiceId, kMethodId> context;
353 
354   struct {
355     bool active = true;
356     Status stream_status = Status::Unknown();
357     int response_value = -1;
358   } result;
359 
360   auto call = test::pw_rpc::pwpb::TestService::TestServerStreamRpc(
361       context.client(),
362       context.channel().id(),
363       {.integer = 123, .status_code = 0},
364       [&result](const test::pwpb::TestStreamResponse::Message& response) {
365         result.active = true;
366         result.response_value = response.number;
367       },
368       [&result](Status status) {
369         result.active = false;
370         result.stream_status = status;
371       });
372 
373   EXPECT_TRUE(call.active());
374 
375   EXPECT_EQ(context.output().total_packets(), 1u);
376   auto packet =
377       static_cast<const internal::test::FakeChannelOutput&>(context.output())
378           .last_packet();
379   EXPECT_EQ(packet.channel_id(), context.channel().id());
380   EXPECT_EQ(packet.service_id(), kServiceId);
381   EXPECT_EQ(packet.method_id(), kMethodId);
382   PW_DECODE_PB(test::pwpb::TestRequest, sent_proto, packet.payload());
383   EXPECT_EQ(sent_proto.integer, 123);
384 
385   PW_ENCODE_PB(
386       test::pwpb::TestStreamResponse, response, .chunk = {}, .number = 11u);
387   EXPECT_EQ(OkStatus(), context.SendServerStream(response));
388   EXPECT_TRUE(result.active);
389   EXPECT_EQ(result.response_value, 11);
390 
391   EXPECT_EQ(OkStatus(), context.SendResponse(Status::NotFound()));
392   EXPECT_FALSE(result.active);
393   EXPECT_EQ(result.stream_status, Status::NotFound());
394 }
395 
396 }  // namespace
397 }  // namespace pw::rpc
398 
399 PW_MODIFY_DIAGNOSTICS_POP();
400