blob: a61394ba6a2c9fe6ae58dbb5e91f39ec04ac94d3 [file] [log] [blame]
Alexei Frolov2b54ee62021-04-29 14:58:21 -07001// Copyright 2021 The Pigweed Authors
Alexei Frolov7fb63af2020-07-09 17:05:52 -07002//
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"
Alexei Frolov15255c52020-07-17 08:25:49 -070016#include "pw_rpc/internal/hash.h"
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070017#include "pw_rpc/internal/test_utils.h"
Wyatt Hepler8ec2cf82021-07-09 17:18:41 -070018#include "pw_rpc/nanopb/test_method_context.h"
Alexei Frolova56482e2020-09-29 11:57:37 -070019#include "pw_rpc_nanopb_private/internal_test_utils.h"
Alexei Frolov3ab26ff2020-07-21 10:44:58 -070020#include "pw_rpc_test_protos/test.rpc.pb.h"
Alexei Frolov7fb63af2020-07-09 17:05:52 -070021
Wyatt Hepler8aa02922020-07-17 08:54:37 -070022namespace pw::rpc {
23namespace test {
24
Alexei Frolov3ab26ff2020-07-21 10:44:58 -070025class TestService final : public generated::TestService<TestService> {
Alexei Frolovabb0f992020-07-17 16:34:41 -070026 public:
Wyatt Hepler82110182021-08-13 11:43:19 -070027 Status TestUnaryRpc(ServerContext&,
28 const pw_rpc_test_TestRequest& request,
29 pw_rpc_test_TestResponse& response) {
Alexei Frolovabb0f992020-07-17 16:34:41 -070030 response.value = request.integer + 1;
31 return static_cast<Status::Code>(request.status_code);
Wyatt Hepler8aa02922020-07-17 08:54:37 -070032 }
33
Wyatt Hepler82110182021-08-13 11:43:19 -070034 static void TestServerStreamRpc(
Wyatt Heplere95bd722020-11-23 07:49:47 -080035 ServerContext&,
36 const pw_rpc_test_TestRequest& request,
37 ServerWriter<pw_rpc_test_TestStreamResponse>& writer) {
Alexei Frolovabb0f992020-07-17 16:34:41 -070038 for (int i = 0; i < request.integer; ++i) {
Wyatt Hepler85eb7c92020-08-06 13:45:20 -070039 writer.Write({.chunk = {}, .number = static_cast<uint32_t>(i)});
Alexei Frolovabb0f992020-07-17 16:34:41 -070040 }
41
42 writer.Finish(static_cast<Status::Code>(request.status_code));
43 }
Wyatt Hepler07e3ba02021-07-02 00:54:13 -070044
45 void TestClientStreamRpc(
46 ServerContext&,
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070047 ServerReader<pw_rpc_test_TestRequest, pw_rpc_test_TestStreamResponse>&
48 new_reader) {
49 reader = std::move(new_reader);
Wyatt Hepler07e3ba02021-07-02 00:54:13 -070050 }
51
52 void TestBidirectionalStreamRpc(
53 ServerContext&,
54 ServerReaderWriter<pw_rpc_test_TestRequest,
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070055 pw_rpc_test_TestStreamResponse>& new_reader_writer) {
56 reader_writer = std::move(new_reader_writer);
Wyatt Hepler07e3ba02021-07-02 00:54:13 -070057 }
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070058
59 ServerReader<pw_rpc_test_TestRequest, pw_rpc_test_TestStreamResponse> reader;
60 ServerReaderWriter<pw_rpc_test_TestRequest, pw_rpc_test_TestStreamResponse>
61 reader_writer;
Alexei Frolovabb0f992020-07-17 16:34:41 -070062};
Wyatt Hepler8aa02922020-07-17 08:54:37 -070063
64} // namespace test
65
Alexei Frolov7fb63af2020-07-09 17:05:52 -070066namespace {
67
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070068using internal::ClientContextForTest;
69
Alexei Frolov7fb63af2020-07-09 17:05:52 -070070TEST(NanopbCodegen, CompilesProperly) {
Alexei Frolov3ab26ff2020-07-21 10:44:58 -070071 test::TestService service;
Wyatt Hepler1532e522020-07-30 11:44:58 -070072 EXPECT_EQ(service.id(), internal::Hash("pw.rpc.test.TestService"));
Alexei Frolov7fb63af2020-07-09 17:05:52 -070073 EXPECT_STREQ(service.name(), "TestService");
74}
75
Alexei Frolova56482e2020-09-29 11:57:37 -070076TEST(NanopbCodegen, Server_InvokeUnaryRpc) {
Wyatt Hepler82110182021-08-13 11:43:19 -070077 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestUnaryRpc) context;
Wyatt Hepler8aa02922020-07-17 08:54:37 -070078
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080079 EXPECT_EQ(OkStatus(),
80 context.call({.integer = 123, .status_code = OkStatus().code()}));
Wyatt Hepler8aa02922020-07-17 08:54:37 -070081
82 EXPECT_EQ(124, context.response().value);
83
Wyatt Heplera17fbdd2020-11-12 11:28:05 -080084 EXPECT_EQ(Status::InvalidArgument(),
85 context.call({.integer = 999,
86 .status_code = Status::InvalidArgument().code()}));
Wyatt Hepler8aa02922020-07-17 08:54:37 -070087 EXPECT_EQ(1000, context.response().value);
88}
89
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -070090TEST(NanopbCodegen, Server_InvokeServerStreamingRpc) {
Wyatt Hepler82110182021-08-13 11:43:19 -070091 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestServerStreamRpc) context;
Wyatt Hepler8aa02922020-07-17 08:54:37 -070092
Wyatt Heplera17fbdd2020-11-12 11:28:05 -080093 context.call({.integer = 0, .status_code = Status::Aborted().code()});
Wyatt Hepler8aa02922020-07-17 08:54:37 -070094
Wyatt Heplerd78f7c62020-09-28 14:27:32 -070095 EXPECT_EQ(Status::Aborted(), context.status());
Wyatt Hepler8aa02922020-07-17 08:54:37 -070096 EXPECT_TRUE(context.done());
97 EXPECT_TRUE(context.responses().empty());
98 EXPECT_EQ(0u, context.total_responses());
99
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800100 context.call({.integer = 4, .status_code = OkStatus().code()});
Wyatt Hepler8aa02922020-07-17 08:54:37 -0700101
102 ASSERT_EQ(4u, context.responses().size());
103 ASSERT_EQ(4u, context.total_responses());
104
105 for (size_t i = 0; i < context.responses().size(); ++i) {
106 EXPECT_EQ(context.responses()[i].number, i);
107 }
108
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800109 EXPECT_EQ(OkStatus().code(), context.status());
Wyatt Hepler8aa02922020-07-17 08:54:37 -0700110}
111
Alexei Frolova56482e2020-09-29 11:57:37 -0700112TEST(NanopbCodegen,
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700113 Server_InvokeServerStreamingRpc_ContextKeepsFixedNumberOfResponses) {
Wyatt Hepler82110182021-08-13 11:43:19 -0700114 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestServerStreamRpc, 3)
115 context;
Wyatt Hepler8aa02922020-07-17 08:54:37 -0700116
117 ASSERT_EQ(3u, context.responses().max_size());
118
Wyatt Heplera17fbdd2020-11-12 11:28:05 -0800119 context.call({.integer = 5, .status_code = Status::NotFound().code()});
Wyatt Hepler8aa02922020-07-17 08:54:37 -0700120
121 ASSERT_EQ(3u, context.responses().size());
122 ASSERT_EQ(5u, context.total_responses());
123
124 EXPECT_EQ(context.responses()[0].number, 0u);
125 EXPECT_EQ(context.responses()[1].number, 1u);
126 EXPECT_EQ(context.responses()[2].number, 4u);
127}
128
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700129TEST(NanopbCodegen, Server_InvokeServerStreamingRpc_ManualWriting) {
Wyatt Hepler82110182021-08-13 11:43:19 -0700130 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestServerStreamRpc, 3)
131 context;
Alexei Frolov91172612020-07-21 17:08:03 -0700132
133 ASSERT_EQ(3u, context.responses().max_size());
134
135 auto writer = context.writer();
136
Wyatt Hepler85eb7c92020-08-06 13:45:20 -0700137 writer.Write({.chunk = {}, .number = 3});
138 writer.Write({.chunk = {}, .number = 6});
139 writer.Write({.chunk = {}, .number = 9});
Alexei Frolov91172612020-07-21 17:08:03 -0700140
141 EXPECT_FALSE(context.done());
142
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700143 writer.Finish(Status::Cancelled());
Alexei Frolov91172612020-07-21 17:08:03 -0700144 ASSERT_TRUE(context.done());
Wyatt Heplerd78f7c62020-09-28 14:27:32 -0700145 EXPECT_EQ(Status::Cancelled(), context.status());
Alexei Frolov91172612020-07-21 17:08:03 -0700146
147 ASSERT_EQ(3u, context.responses().size());
148 ASSERT_EQ(3u, context.total_responses());
149
150 EXPECT_EQ(context.responses()[0].number, 3u);
151 EXPECT_EQ(context.responses()[1].number, 6u);
152 EXPECT_EQ(context.responses()[2].number, 9u);
153}
154
Wyatt Heplerfa6edcc2021-08-20 08:30:08 -0700155TEST(NanopbCodegen, Server_InvokeClientStreamingRpc) {
156 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestClientStreamRpc) context;
157
158 context.call();
159
160 pw_rpc_test_TestRequest request = {};
161 context.service().reader.set_on_next(
162 [&request](const pw_rpc_test_TestRequest& req) { request = req; });
163
164 context.SendClientStream({.integer = -99, .status_code = 10});
165 EXPECT_EQ(request.integer, -99);
166 EXPECT_EQ(request.status_code, 10u);
167
168 ASSERT_EQ(OkStatus(),
169 context.service().reader.Finish({.chunk = {}, .number = 3},
170 Status::Unimplemented()));
171 EXPECT_EQ(Status::Unimplemented(), context.status());
172 EXPECT_EQ(context.response().number, 3u);
173}
174
175TEST(NanopbCodegen, Server_InvokeBidirectionalStreamingRpc) {
176 PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestBidirectionalStreamRpc)
177 context;
178
179 context.call();
180
181 pw_rpc_test_TestRequest request = {};
182 context.service().reader_writer.set_on_next(
183 [&request](const pw_rpc_test_TestRequest& req) { request = req; });
184
185 context.SendClientStream({.integer = -99, .status_code = 10});
186 EXPECT_EQ(request.integer, -99);
187 EXPECT_EQ(request.status_code, 10u);
188
189 ASSERT_EQ(OkStatus(),
190 context.service().reader_writer.Write({.chunk = {}, .number = 2}));
191 EXPECT_EQ(context.responses()[0].number, 2u);
192
193 ASSERT_EQ(OkStatus(),
194 context.service().reader_writer.Finish(Status::NotFound()));
195 EXPECT_EQ(Status::NotFound(), context.status());
196}
197
Alexei Frolova56482e2020-09-29 11:57:37 -0700198using TestServiceClient = test::nanopb::TestServiceClient;
Alexei Frolova56482e2020-09-29 11:57:37 -0700199
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700200TEST(NanopbCodegen, Client_GeneratesCallAliases) {
201 static_assert(
Wyatt Hepler82110182021-08-13 11:43:19 -0700202 std::is_same_v<TestServiceClient::TestUnaryRpcCall,
Alexei Frolovbebba902021-06-09 17:03:52 -0700203 NanopbClientCall<
204 internal::UnaryCallbacks<pw_rpc_test_TestResponse>>>);
205 static_assert(
Wyatt Hepler82110182021-08-13 11:43:19 -0700206 std::is_same_v<TestServiceClient::TestServerStreamRpcCall,
Alexei Frolovbebba902021-06-09 17:03:52 -0700207 NanopbClientCall<internal::ServerStreamingCallbacks<
208 pw_rpc_test_TestStreamResponse>>>);
Alexei Frolov2b54ee62021-04-29 14:58:21 -0700209}
210
Alexei Froloveafe2192021-06-18 16:03:09 -0700211TEST(NanopbCodegen, ClientCall_DefaultConstructor) {
Wyatt Hepler82110182021-08-13 11:43:19 -0700212 TestServiceClient::TestUnaryRpcCall unary_call;
213 TestServiceClient::TestServerStreamRpcCall server_streaming_call;
Alexei Froloveafe2192021-06-18 16:03:09 -0700214}
215
Alexei Frolova56482e2020-09-29 11:57:37 -0700216TEST(NanopbCodegen, Client_InvokesUnaryRpcWithCallback) {
217 constexpr uint32_t service_id = internal::Hash("pw.rpc.test.TestService");
Wyatt Hepler82110182021-08-13 11:43:19 -0700218 constexpr uint32_t method_id = internal::Hash("TestUnaryRpc");
Alexei Frolova56482e2020-09-29 11:57:37 -0700219
220 ClientContextForTest<128, 128, 99, service_id, method_id> context;
Alexei Frolovbebba902021-06-09 17:03:52 -0700221
222 struct {
223 Status last_status = Status::Unknown();
224 int response_value = -1;
225 } result;
Alexei Frolova56482e2020-09-29 11:57:37 -0700226
Wyatt Hepler82110182021-08-13 11:43:19 -0700227 auto call = TestServiceClient::TestUnaryRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700228 context.channel(),
229 {.integer = 123, .status_code = 0},
230 [&result](const pw_rpc_test_TestResponse& response, Status status) {
231 result.last_status = status;
232 result.response_value = response.value;
233 });
234
Alexei Frolova56482e2020-09-29 11:57:37 -0700235 EXPECT_EQ(context.output().packet_count(), 1u);
236 auto packet = context.output().sent_packet();
237 EXPECT_EQ(packet.channel_id(), context.channel().id());
238 EXPECT_EQ(packet.service_id(), service_id);
239 EXPECT_EQ(packet.method_id(), method_id);
240 PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
241 EXPECT_EQ(sent_proto.integer, 123);
242
243 PW_ENCODE_PB(pw_rpc_test_TestResponse, response, .value = 42);
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -0800244 context.SendResponse(OkStatus(), response);
Alexei Frolovbebba902021-06-09 17:03:52 -0700245 EXPECT_EQ(result.last_status, OkStatus());
246 EXPECT_EQ(result.response_value, 42);
Alexei Frolova56482e2020-09-29 11:57:37 -0700247}
248
249TEST(NanopbCodegen, Client_InvokesServerStreamingRpcWithCallback) {
250 constexpr uint32_t service_id = internal::Hash("pw.rpc.test.TestService");
Wyatt Hepler82110182021-08-13 11:43:19 -0700251 constexpr uint32_t method_id = internal::Hash("TestServerStreamRpc");
Alexei Frolova56482e2020-09-29 11:57:37 -0700252
253 ClientContextForTest<128, 128, 99, service_id, method_id> context;
Alexei Frolovbebba902021-06-09 17:03:52 -0700254
255 struct {
256 bool active = true;
257 Status stream_status = Status::Unknown();
258 int response_value = -1;
259 } result;
Alexei Frolova56482e2020-09-29 11:57:37 -0700260
Wyatt Hepler82110182021-08-13 11:43:19 -0700261 auto call = TestServiceClient::TestServerStreamRpc(
Alexei Frolovbebba902021-06-09 17:03:52 -0700262 context.channel(),
263 {.integer = 123, .status_code = 0},
264 [&result](const pw_rpc_test_TestStreamResponse& response) {
265 result.active = true;
266 result.response_value = response.number;
267 },
268 [&result](Status status) {
269 result.active = false;
270 result.stream_status = status;
271 });
272
Alexei Frolova56482e2020-09-29 11:57:37 -0700273 EXPECT_EQ(context.output().packet_count(), 1u);
274 auto packet = context.output().sent_packet();
275 EXPECT_EQ(packet.channel_id(), context.channel().id());
276 EXPECT_EQ(packet.service_id(), service_id);
277 EXPECT_EQ(packet.method_id(), method_id);
278 PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
279 EXPECT_EQ(sent_proto.integer, 123);
280
281 PW_ENCODE_PB(
282 pw_rpc_test_TestStreamResponse, response, .chunk = {}, .number = 11u);
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700283 context.SendServerStream(response);
Alexei Frolovbebba902021-06-09 17:03:52 -0700284 EXPECT_TRUE(result.active);
285 EXPECT_EQ(result.response_value, 11);
Alexei Frolova56482e2020-09-29 11:57:37 -0700286
Wyatt Hepler5ba80642021-06-18 12:56:17 -0700287 context.SendResponse(Status::NotFound());
Alexei Frolovbebba902021-06-09 17:03:52 -0700288 EXPECT_FALSE(result.active);
289 EXPECT_EQ(result.stream_status, Status::NotFound());
Alexei Frolova56482e2020-09-29 11:57:37 -0700290}
291
Alexei Frolov7fb63af2020-07-09 17:05:52 -0700292} // namespace
Wyatt Hepler8aa02922020-07-17 08:54:37 -0700293} // namespace pw::rpc