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