blob: bbb939b4cac8fb66870949da6dddab1705e0e877 [file] [log] [blame]
Alexei Frolov4d2adde2020-08-04 10:19:24 -07001// 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
Wyatt Hepler8ec2cf82021-07-09 17:18:41 -070015#include "pw_rpc/nanopb/client_call.h"
Alexei Frolov4d2adde2020-08-04 10:19:24 -070016
17#include "gtest/gtest.h"
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070018#include "pw_rpc/internal/test_utils.h"
Alexei Frolov4d2adde2020-08-04 10:19:24 -070019#include "pw_rpc_nanopb_private/internal_test_utils.h"
Alexei Frolov4d2adde2020-08-04 10:19:24 -070020#include "pw_rpc_test_protos/test.pb.h"
21
22namespace pw::rpc {
23namespace {
24
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070025using internal::ClientContextForTest;
26
Alexei Frolov4d2adde2020-08-04 10:19:24 -070027constexpr uint32_t kServiceId = 16;
28constexpr uint32_t kUnaryMethodId = 111;
29constexpr uint32_t kServerStreamingMethodId = 112;
30
31class FakeGeneratedServiceClient {
32 public:
Alexei Frolovbebba902021-06-09 17:03:52 -070033 static NanopbClientCall<internal::UnaryCallbacks<pw_rpc_test_TestResponse>>
Wyatt Hepler82110182021-08-13 11:43:19 -070034 TestUnaryRpc(
35 Channel& channel,
36 const pw_rpc_test_TestRequest& request,
37 Function<void(const pw_rpc_test_TestResponse&, Status)> on_response,
38 Function<void(Status)> on_error = nullptr) {
Alexei Frolovbebba902021-06-09 17:03:52 -070039 auto call = NanopbClientCall(
40 &channel,
41 kServiceId,
42 kUnaryMethodId,
43 internal::UnaryCallbacks(std::move(on_response), std::move(on_error)),
44 pw_rpc_test_TestRequest_fields,
45 pw_rpc_test_TestResponse_fields);
Alexei Frolov4d2adde2020-08-04 10:19:24 -070046 call.SendRequest(&request);
47 return call;
48 }
49
50 static NanopbClientCall<
Alexei Frolovbebba902021-06-09 17:03:52 -070051 internal::ServerStreamingCallbacks<pw_rpc_test_TestStreamResponse>>
Wyatt Hepler82110182021-08-13 11:43:19 -070052 TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -070053 Channel& channel,
54 const pw_rpc_test_TestRequest& request,
55 Function<void(const pw_rpc_test_TestStreamResponse&)> on_response,
56 Function<void(Status)> on_stream_end,
57 Function<void(Status)> on_error = nullptr) {
58 auto call = NanopbClientCall(
59 &channel,
60 kServiceId,
61 kServerStreamingMethodId,
62 internal::ServerStreamingCallbacks(std::move(on_response),
63 std::move(on_stream_end),
64 std::move(on_error)),
65 pw_rpc_test_TestRequest_fields,
66 pw_rpc_test_TestStreamResponse_fields);
Alexei Frolov4d2adde2020-08-04 10:19:24 -070067 call.SendRequest(&request);
68 return call;
69 }
70};
71
Alexei Frolov4d2adde2020-08-04 10:19:24 -070072TEST(NanopbClientCall, Unary_SendsRequestPacket) {
73 ClientContextForTest context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -070074
Wyatt Hepler82110182021-08-13 11:43:19 -070075 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -070076 context.channel(), {.integer = 123, .status_code = 0}, nullptr);
Alexei Frolov4d2adde2020-08-04 10:19:24 -070077
78 EXPECT_EQ(context.output().packet_count(), 1u);
79 auto packet = context.output().sent_packet();
80 EXPECT_EQ(packet.channel_id(), context.channel().id());
81 EXPECT_EQ(packet.service_id(), kServiceId);
82 EXPECT_EQ(packet.method_id(), kUnaryMethodId);
83
84 PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
85 EXPECT_EQ(sent_proto.integer, 123);
86}
87
Alexei Frolovbebba902021-06-09 17:03:52 -070088class UnaryClientCall : public ::testing::Test {
89 protected:
90 Status last_status_ = Status::Unknown();
91 Status last_error_ = Status::Unknown();
92 int responses_received_ = 0;
93 int last_response_value_ = 0;
94};
95
96TEST_F(UnaryClientCall, InvokesCallbackOnValidResponse) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -070097 ClientContextForTest context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -070098
Wyatt Hepler82110182021-08-13 11:43:19 -070099 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700100 context.channel(),
101 {.integer = 123, .status_code = 0},
102 [this](const pw_rpc_test_TestResponse& response, Status status) {
103 ++responses_received_;
104 last_status_ = status;
105 last_response_value_ = response.value;
106 });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700107
108 PW_ENCODE_PB(pw_rpc_test_TestResponse, response, .value = 42);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800109 context.SendResponse(OkStatus(), response);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700110
Alexei Frolovbebba902021-06-09 17:03:52 -0700111 ASSERT_EQ(responses_received_, 1);
112 EXPECT_EQ(last_status_, OkStatus());
113 EXPECT_EQ(last_response_value_, 42);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700114}
115
Alexei Frolovbebba902021-06-09 17:03:52 -0700116TEST_F(UnaryClientCall, DoesNothingOnNullCallback) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700117 ClientContextForTest context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700118
Wyatt Hepler82110182021-08-13 11:43:19 -0700119 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700120 context.channel(), {.integer = 123, .status_code = 0}, nullptr);
121
122 PW_ENCODE_PB(pw_rpc_test_TestResponse, response, .value = 42);
123 context.SendResponse(OkStatus(), response);
124
125 ASSERT_EQ(responses_received_, 0);
126}
127
128TEST_F(UnaryClientCall, InvokesErrorCallbackOnInvalidResponse) {
129 ClientContextForTest context;
130
Wyatt Hepler82110182021-08-13 11:43:19 -0700131 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700132 context.channel(),
133 {.integer = 123, .status_code = 0},
134 [this](const pw_rpc_test_TestResponse& response, Status status) {
135 ++responses_received_;
136 last_status_ = status;
137 last_response_value_ = response.value;
138 },
139 [this](Status status) { last_error_ = status; });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700140
141 constexpr std::byte bad_payload[]{
142 std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}};
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800143 context.SendResponse(OkStatus(), bad_payload);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700144
Alexei Frolovbebba902021-06-09 17:03:52 -0700145 EXPECT_EQ(responses_received_, 0);
146 EXPECT_EQ(last_error_, Status::DataLoss());
Alexei Frolovd7276222020-10-01 12:41:59 -0700147}
148
Alexei Frolovbebba902021-06-09 17:03:52 -0700149TEST_F(UnaryClientCall, InvokesErrorCallbackOnServerError) {
Alexei Frolovd7276222020-10-01 12:41:59 -0700150 ClientContextForTest context;
Alexei Frolovd7276222020-10-01 12:41:59 -0700151
Wyatt Hepler82110182021-08-13 11:43:19 -0700152 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700153 context.channel(),
154 {.integer = 123, .status_code = 0},
155 [this](const pw_rpc_test_TestResponse& response, Status status) {
156 ++responses_received_;
157 last_status_ = status;
158 last_response_value_ = response.value;
159 },
160 [this](Status status) { last_error_ = status; });
Alexei Frolovd7276222020-10-01 12:41:59 -0700161
162 context.SendPacket(internal::PacketType::SERVER_ERROR, Status::NotFound());
163
Alexei Frolovbebba902021-06-09 17:03:52 -0700164 EXPECT_EQ(responses_received_, 0);
165 EXPECT_EQ(last_error_, Status::NotFound());
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700166}
167
Alexei Frolovbebba902021-06-09 17:03:52 -0700168TEST_F(UnaryClientCall, DoesNothingOnErrorWithoutCallback) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700169 ClientContextForTest context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700170
Wyatt Hepler82110182021-08-13 11:43:19 -0700171 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700172 context.channel(),
173 {.integer = 123, .status_code = 0},
174 [this](const pw_rpc_test_TestResponse& response, Status status) {
175 ++responses_received_;
176 last_status_ = status;
177 last_response_value_ = response.value;
178 });
179
180 constexpr std::byte bad_payload[]{
181 std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}};
182 context.SendResponse(OkStatus(), bad_payload);
183
184 EXPECT_EQ(responses_received_, 0);
185}
186
187TEST_F(UnaryClientCall, OnlyReceivesOneResponse) {
188 ClientContextForTest context;
189
Wyatt Hepler82110182021-08-13 11:43:19 -0700190 auto call = FakeGeneratedServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700191 context.channel(),
192 {.integer = 123, .status_code = 0},
193 [this](const pw_rpc_test_TestResponse& response, Status status) {
194 ++responses_received_;
195 last_status_ = status;
196 last_response_value_ = response.value;
197 });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700198
199 PW_ENCODE_PB(pw_rpc_test_TestResponse, r1, .value = 42);
200 context.SendResponse(Status::Unimplemented(), r1);
201 PW_ENCODE_PB(pw_rpc_test_TestResponse, r2, .value = 44);
202 context.SendResponse(Status::OutOfRange(), r2);
203 PW_ENCODE_PB(pw_rpc_test_TestResponse, r3, .value = 46);
204 context.SendResponse(Status::Internal(), r3);
205
Alexei Frolovbebba902021-06-09 17:03:52 -0700206 EXPECT_EQ(responses_received_, 1);
207 EXPECT_EQ(last_status_, Status::Unimplemented());
208 EXPECT_EQ(last_response_value_, 42);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700209}
210
Alexei Frolovbebba902021-06-09 17:03:52 -0700211class ServerStreamingClientCall : public ::testing::Test {
212 protected:
213 bool active_ = true;
214 Status stream_status_ = Status::Unknown();
215 Status rpc_error_ = Status::Unknown();
216 int responses_received_ = 0;
217 int last_response_number_ = 0;
218};
219
220TEST_F(ServerStreamingClientCall, SendsRequestPacket) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700221 ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
222 context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700223
Wyatt Hepler82110182021-08-13 11:43:19 -0700224 auto call = FakeGeneratedServiceClient::TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700225 context.channel(), {.integer = 71, .status_code = 0}, nullptr, nullptr);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700226
227 EXPECT_EQ(context.output().packet_count(), 1u);
228 auto packet = context.output().sent_packet();
229 EXPECT_EQ(packet.channel_id(), context.channel().id());
230 EXPECT_EQ(packet.service_id(), kServiceId);
231 EXPECT_EQ(packet.method_id(), kServerStreamingMethodId);
232
233 PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
234 EXPECT_EQ(sent_proto.integer, 71);
235}
236
Alexei Frolovbebba902021-06-09 17:03:52 -0700237TEST_F(ServerStreamingClientCall, InvokesCallbackOnValidResponse) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700238 ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
239 context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700240
Wyatt Hepler82110182021-08-13 11:43:19 -0700241 auto call = FakeGeneratedServiceClient::TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700242 context.channel(),
243 {.integer = 71, .status_code = 0},
244 [this](const pw_rpc_test_TestStreamResponse& response) {
245 ++responses_received_;
246 last_response_number_ = response.number;
247 },
248 [this](Status status) {
249 active_ = false;
250 stream_status_ = status;
251 });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700252
253 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700254 context.SendServerStream(r1);
Alexei Frolovbebba902021-06-09 17:03:52 -0700255 EXPECT_TRUE(active_);
256 EXPECT_EQ(responses_received_, 1);
257 EXPECT_EQ(last_response_number_, 11);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700258
259 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700260 context.SendServerStream(r2);
Alexei Frolovbebba902021-06-09 17:03:52 -0700261 EXPECT_TRUE(active_);
262 EXPECT_EQ(responses_received_, 2);
263 EXPECT_EQ(last_response_number_, 22);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700264
265 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r3, .chunk = {}, .number = 33u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700266 context.SendServerStream(r3);
Alexei Frolovbebba902021-06-09 17:03:52 -0700267 EXPECT_TRUE(active_);
268 EXPECT_EQ(responses_received_, 3);
269 EXPECT_EQ(last_response_number_, 33);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700270}
271
Alexei Frolovbebba902021-06-09 17:03:52 -0700272TEST_F(ServerStreamingClientCall, InvokesStreamEndOnFinish) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700273 ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
274 context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700275
Wyatt Hepler82110182021-08-13 11:43:19 -0700276 auto call = FakeGeneratedServiceClient::TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700277 context.channel(),
278 {.integer = 71, .status_code = 0},
279 [this](const pw_rpc_test_TestStreamResponse& response) {
280 ++responses_received_;
281 last_response_number_ = response.number;
282 },
283 [this](Status status) {
284 active_ = false;
285 stream_status_ = status;
286 });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700287
288 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700289 context.SendServerStream(r1);
Alexei Frolovbebba902021-06-09 17:03:52 -0700290 EXPECT_TRUE(active_);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700291
292 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700293 context.SendServerStream(r2);
Alexei Frolovbebba902021-06-09 17:03:52 -0700294 EXPECT_TRUE(active_);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700295
296 // Close the stream.
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700297 context.SendResponse(Status::NotFound());
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700298
299 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r3, .chunk = {}, .number = 33u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700300 context.SendServerStream(r3);
Alexei Frolovbebba902021-06-09 17:03:52 -0700301 EXPECT_FALSE(active_);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700302
Alexei Frolovbebba902021-06-09 17:03:52 -0700303 EXPECT_EQ(responses_received_, 2);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700304}
305
Alexei Frolovbebba902021-06-09 17:03:52 -0700306TEST_F(ServerStreamingClientCall, InvokesErrorCallbackOnInvalidResponses) {
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700307 ClientContextForTest<128, 128, 99, kServiceId, kServerStreamingMethodId>
308 context;
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700309
Wyatt Hepler82110182021-08-13 11:43:19 -0700310 auto call = FakeGeneratedServiceClient::TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700311 context.channel(),
312 {.integer = 71, .status_code = 0},
313 [this](const pw_rpc_test_TestStreamResponse& response) {
314 ++responses_received_;
315 last_response_number_ = response.number;
316 },
317 nullptr,
318 [this](Status error) { rpc_error_ = error; });
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700319
320 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r1, .chunk = {}, .number = 11u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700321 context.SendServerStream(r1);
Alexei Frolovbebba902021-06-09 17:03:52 -0700322 EXPECT_TRUE(active_);
323 EXPECT_EQ(responses_received_, 1);
324 EXPECT_EQ(last_response_number_, 11);
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700325
326 constexpr std::byte bad_payload[]{
327 std::byte{0xab}, std::byte{0xcd}, std::byte{0xef}};
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700328 context.SendServerStream(bad_payload);
Alexei Frolovbebba902021-06-09 17:03:52 -0700329 EXPECT_EQ(responses_received_, 1);
330 EXPECT_EQ(rpc_error_, Status::DataLoss());
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700331
332 PW_ENCODE_PB(pw_rpc_test_TestStreamResponse, r2, .chunk = {}, .number = 22u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700333 context.SendServerStream(r2);
Alexei Frolovbebba902021-06-09 17:03:52 -0700334 EXPECT_TRUE(active_);
335 EXPECT_EQ(responses_received_, 2);
336 EXPECT_EQ(last_response_number_, 22);
Alexei Frolovd7276222020-10-01 12:41:59 -0700337
338 context.SendPacket(internal::PacketType::SERVER_ERROR, Status::NotFound());
Alexei Frolovbebba902021-06-09 17:03:52 -0700339 EXPECT_EQ(responses_received_, 2);
340 EXPECT_EQ(rpc_error_, Status::NotFound());
Alexei Frolov4d2adde2020-08-04 10:19:24 -0700341}
342
343} // namespace
344} // namespace pw::rpc