• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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_rpc/nanopb_client_call.h"
16 
17 #include "gtest/gtest.h"
18 #include "pw_rpc_nanopb_private/internal_test_utils.h"
19 #include "pw_rpc_private/internal_test_utils.h"
20 #include "pw_rpc_test_protos/test.pb.h"
21 
22 namespace pw::rpc {
23 namespace {
24 
25 constexpr uint32_t kServiceId = 16;
26 constexpr uint32_t kUnaryMethodId = 111;
27 constexpr uint32_t kServerStreamingMethodId = 112;
28 
29 class FakeGeneratedServiceClient {
30  public:
31   static NanopbClientCall<UnaryResponseHandler<pw_rpc_test_TestResponse>>
TestRpc(Channel & channel,const pw_rpc_test_TestRequest & request,UnaryResponseHandler<pw_rpc_test_TestResponse> & callback)32   TestRpc(Channel& channel,
33           const pw_rpc_test_TestRequest& request,
34           UnaryResponseHandler<pw_rpc_test_TestResponse>& callback) {
35     auto call = NanopbClientCall(&channel,
36                                  kServiceId,
37                                  kUnaryMethodId,
38                                  callback,
39                                  pw_rpc_test_TestRequest_fields,
40                                  pw_rpc_test_TestResponse_fields);
41     call.SendRequest(&request);
42     return call;
43   }
44 
45   static NanopbClientCall<
46       ServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse>>
TestStreamRpc(Channel & channel,const pw_rpc_test_TestRequest & request,ServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> & callback)47   TestStreamRpc(Channel& channel,
48                 const pw_rpc_test_TestRequest& request,
49                 ServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse>&
50                     callback) {
51     auto call = NanopbClientCall(&channel,
52                                  kServiceId,
53                                  kServerStreamingMethodId,
54                                  callback,
55                                  pw_rpc_test_TestRequest_fields,
56                                  pw_rpc_test_TestStreamResponse_fields);
57     call.SendRequest(&request);
58     return call;
59   }
60 };
61 
62 using internal::TestServerStreamingResponseHandler;
63 using internal::TestUnaryResponseHandler;
64 
TEST(NanopbClientCall,Unary_SendsRequestPacket)65 TEST(NanopbClientCall, Unary_SendsRequestPacket) {
66   ClientContextForTest context;
67   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
68 
69   auto call = FakeGeneratedServiceClient::TestRpc(
70       context.channel(), {.integer = 123, .status_code = 0}, handler);
71 
72   EXPECT_EQ(context.output().packet_count(), 1u);
73   auto packet = context.output().sent_packet();
74   EXPECT_EQ(packet.channel_id(), context.channel().id());
75   EXPECT_EQ(packet.service_id(), kServiceId);
76   EXPECT_EQ(packet.method_id(), kUnaryMethodId);
77 
78   PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
79   EXPECT_EQ(sent_proto.integer, 123);
80 }
81 
TEST(NanopbClientCall,Unary_InvokesCallbackOnValidResponse)82 TEST(NanopbClientCall, Unary_InvokesCallbackOnValidResponse) {
83   ClientContextForTest context;
84   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
85 
86   auto call = FakeGeneratedServiceClient::TestRpc(
87       context.channel(), {.integer = 123, .status_code = 0}, handler);
88 
89   PW_ENCODE_PB(pw_rpc_test_TestResponse, response, .value = 42);
90   context.SendResponse(OkStatus(), response);
91 
92   ASSERT_EQ(handler.responses_received(), 1u);
93   EXPECT_EQ(handler.last_status(), OkStatus());
94   EXPECT_EQ(handler.last_response().value, 42);
95 }
96 
TEST(NanopbClientCall,Unary_InvokesErrorCallbackOnInvalidResponse)97 TEST(NanopbClientCall, Unary_InvokesErrorCallbackOnInvalidResponse) {
98   ClientContextForTest context;
99   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
100 
101   auto call = FakeGeneratedServiceClient::TestRpc(
102       context.channel(), {.integer = 123, .status_code = 0}, handler);
103 
104   constexpr std::byte bad_payload[]{
105       std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}};
106   context.SendResponse(OkStatus(), bad_payload);
107 
108   EXPECT_EQ(handler.responses_received(), 0u);
109   EXPECT_EQ(handler.rpc_error(), Status::DataLoss());
110 }
111 
TEST(NanopbClientCall,Unary_InvokesErrorCallbackOnServerError)112 TEST(NanopbClientCall, Unary_InvokesErrorCallbackOnServerError) {
113   ClientContextForTest context;
114   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
115 
116   auto call = FakeGeneratedServiceClient::TestRpc(
117       context.channel(), {.integer = 123, .status_code = 0}, handler);
118 
119   context.SendPacket(internal::PacketType::SERVER_ERROR, Status::NotFound());
120 
121   EXPECT_EQ(handler.responses_received(), 0u);
122   EXPECT_EQ(handler.rpc_error(), Status::NotFound());
123 }
124 
TEST(NanopbClientCall,Unary_OnlyReceivesOneResponse)125 TEST(NanopbClientCall, Unary_OnlyReceivesOneResponse) {
126   ClientContextForTest context;
127   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
128 
129   auto call = FakeGeneratedServiceClient::TestRpc(
130       context.channel(), {.integer = 123, .status_code = 0}, handler);
131 
132   PW_ENCODE_PB(pw_rpc_test_TestResponse, r1, .value = 42);
133   context.SendResponse(Status::Unimplemented(), r1);
134   PW_ENCODE_PB(pw_rpc_test_TestResponse, r2, .value = 44);
135   context.SendResponse(Status::OutOfRange(), r2);
136   PW_ENCODE_PB(pw_rpc_test_TestResponse, r3, .value = 46);
137   context.SendResponse(Status::Internal(), r3);
138 
139   EXPECT_EQ(handler.responses_received(), 1u);
140   EXPECT_EQ(handler.last_status(), Status::Unimplemented());
141   EXPECT_EQ(handler.last_response().value, 42);
142 }
143 
TEST(NanopbClientCall,ServerStreaming_SendsRequestPacket)144 TEST(NanopbClientCall, ServerStreaming_SendsRequestPacket) {
145   ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
146       context;
147   TestServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> handler;
148 
149   auto call = FakeGeneratedServiceClient::TestStreamRpc(
150       context.channel(), {.integer = 71, .status_code = 0}, handler);
151 
152   EXPECT_EQ(context.output().packet_count(), 1u);
153   auto packet = context.output().sent_packet();
154   EXPECT_EQ(packet.channel_id(), context.channel().id());
155   EXPECT_EQ(packet.service_id(), kServiceId);
156   EXPECT_EQ(packet.method_id(), kServerStreamingMethodId);
157 
158   PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
159   EXPECT_EQ(sent_proto.integer, 71);
160 }
161 
TEST(NanopbClientCall,ServerStreaming_InvokesCallbackOnValidResponse)162 TEST(NanopbClientCall, ServerStreaming_InvokesCallbackOnValidResponse) {
163   ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
164       context;
165   TestServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> handler;
166 
167   auto call = FakeGeneratedServiceClient::TestStreamRpc(
168       context.channel(), {.integer = 71, .status_code = 0}, handler);
169 
170   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
171   context.SendResponse(OkStatus(), r1);
172   EXPECT_TRUE(handler.active());
173   EXPECT_EQ(handler.responses_received(), 1u);
174   EXPECT_EQ(handler.last_response().number, 11u);
175 
176   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
177   context.SendResponse(OkStatus(), r2);
178   EXPECT_TRUE(handler.active());
179   EXPECT_EQ(handler.responses_received(), 2u);
180   EXPECT_EQ(handler.last_response().number, 22u);
181 
182   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r3, .chunk = {}, .number = 33u);
183   context.SendResponse(OkStatus(), r3);
184   EXPECT_TRUE(handler.active());
185   EXPECT_EQ(handler.responses_received(), 3u);
186   EXPECT_EQ(handler.last_response().number, 33u);
187 }
188 
TEST(NanopbClientCall,ServerStreaming_ClosesOnFinish)189 TEST(NanopbClientCall, ServerStreaming_ClosesOnFinish) {
190   ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
191       context;
192   TestServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> handler;
193 
194   auto call = FakeGeneratedServiceClient::TestStreamRpc(
195       context.channel(), {.integer = 71, .status_code = 0}, handler);
196 
197   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
198   context.SendResponse(OkStatus(), r1);
199   EXPECT_TRUE(handler.active());
200 
201   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
202   context.SendResponse(OkStatus(), r2);
203   EXPECT_TRUE(handler.active());
204 
205   // Close the stream.
206   context.SendPacket(internal::PacketType::SERVER_STREAM_END,
207                      Status::NotFound());
208 
209   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r3, .chunk = {}, .number = 33u);
210   context.SendResponse(OkStatus(), r3);
211   EXPECT_FALSE(handler.active());
212 
213   EXPECT_EQ(handler.responses_received(), 2u);
214 }
215 
TEST(NanopbClientCall,ServerStreaming_InvokesErrorCallbackOnInvalidResponses)216 TEST(NanopbClientCall, ServerStreaming_InvokesErrorCallbackOnInvalidResponses) {
217   ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
218       context;
219   TestServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> handler;
220 
221   auto call = FakeGeneratedServiceClient::TestStreamRpc(
222       context.channel(), {.integer = 71, .status_code = 0}, handler);
223 
224   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
225   context.SendResponse(OkStatus(), r1);
226   EXPECT_TRUE(handler.active());
227   EXPECT_EQ(handler.responses_received(), 1u);
228   EXPECT_EQ(handler.last_response().number, 11u);
229 
230   constexpr std::byte bad_payload[]{
231       std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}};
232   context.SendResponse(OkStatus(), bad_payload);
233   EXPECT_EQ(handler.responses_received(), 1u);
234   EXPECT_EQ(handler.rpc_error(), Status::DataLoss());
235 
236   PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
237   context.SendResponse(OkStatus(), r2);
238   EXPECT_TRUE(handler.active());
239   EXPECT_EQ(handler.responses_received(), 2u);
240   EXPECT_EQ(handler.last_response().number, 22u);
241 
242   context.SendPacket(internal::PacketType::SERVER_ERROR, Status::NotFound());
243   EXPECT_EQ(handler.responses_received(), 2u);
244   EXPECT_EQ(handler.rpc_error(), Status::NotFound());
245 }
246 
247 }  // namespace
248 }  // namespace pw::rpc
249