• 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 "gtest/gtest.h"
16 #include "pw_rpc/internal/hash.h"
17 #include "pw_rpc/nanopb_test_method_context.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.rpc.pb.h"
21 
22 namespace pw::rpc {
23 namespace test {
24 
25 class TestService final : public generated::TestService<TestService> {
26  public:
TestRpc(ServerContext &,const pw_rpc_test_TestRequest & request,pw_rpc_test_TestResponse & response)27   Status TestRpc(ServerContext&,
28                  const pw_rpc_test_TestRequest& request,
29                  pw_rpc_test_TestResponse& response) {
30     response.value = request.integer + 1;
31     return static_cast<Status::Code>(request.status_code);
32   }
33 
TestStreamRpc(ServerContext &,const pw_rpc_test_TestRequest & request,ServerWriter<pw_rpc_test_TestStreamResponse> & writer)34   static void TestStreamRpc(
35       ServerContext&,
36       const pw_rpc_test_TestRequest& request,
37       ServerWriter<pw_rpc_test_TestStreamResponse>& writer) {
38     for (int i = 0; i < request.integer; ++i) {
39       writer.Write({.chunk = {}, .number = static_cast<uint32_t>(i)});
40     }
41 
42     writer.Finish(static_cast<Status::Code>(request.status_code));
43   }
44 };
45 
46 }  // namespace test
47 
48 namespace {
49 
TEST(NanopbCodegen,CompilesProperly)50 TEST(NanopbCodegen, CompilesProperly) {
51   test::TestService service;
52   EXPECT_EQ(service.id(), internal::Hash("pw.rpc.test.TestService"));
53   EXPECT_STREQ(service.name(), "TestService");
54 }
55 
TEST(NanopbCodegen,Server_InvokeUnaryRpc)56 TEST(NanopbCodegen, Server_InvokeUnaryRpc) {
57   PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestRpc) context;
58 
59   EXPECT_EQ(OkStatus(),
60             context.call({.integer = 123, .status_code = OkStatus().code()}));
61 
62   EXPECT_EQ(124, context.response().value);
63 
64   EXPECT_EQ(Status::InvalidArgument(),
65             context.call({.integer = 999,
66                           .status_code = Status::InvalidArgument().code()}));
67   EXPECT_EQ(1000, context.response().value);
68 }
69 
TEST(NanopbCodegen,Server_InvokeStreamingRpc)70 TEST(NanopbCodegen, Server_InvokeStreamingRpc) {
71   PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestStreamRpc) context;
72 
73   context.call({.integer = 0, .status_code = Status::Aborted().code()});
74 
75   EXPECT_EQ(Status::Aborted(), context.status());
76   EXPECT_TRUE(context.done());
77   EXPECT_TRUE(context.responses().empty());
78   EXPECT_EQ(0u, context.total_responses());
79 
80   context.call({.integer = 4, .status_code = OkStatus().code()});
81 
82   ASSERT_EQ(4u, context.responses().size());
83   ASSERT_EQ(4u, context.total_responses());
84 
85   for (size_t i = 0; i < context.responses().size(); ++i) {
86     EXPECT_EQ(context.responses()[i].number, i);
87   }
88 
89   EXPECT_EQ(OkStatus().code(), context.status());
90 }
91 
TEST(NanopbCodegen,Server_InvokeStreamingRpc_ContextKeepsFixedNumberOfResponses)92 TEST(NanopbCodegen,
93      Server_InvokeStreamingRpc_ContextKeepsFixedNumberOfResponses) {
94   PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestStreamRpc, 3) context;
95 
96   ASSERT_EQ(3u, context.responses().max_size());
97 
98   context.call({.integer = 5, .status_code = Status::NotFound().code()});
99 
100   ASSERT_EQ(3u, context.responses().size());
101   ASSERT_EQ(5u, context.total_responses());
102 
103   EXPECT_EQ(context.responses()[0].number, 0u);
104   EXPECT_EQ(context.responses()[1].number, 1u);
105   EXPECT_EQ(context.responses()[2].number, 4u);
106 }
107 
TEST(NanopbCodegen,Server_InvokeStreamingRpc_ManualWriting)108 TEST(NanopbCodegen, Server_InvokeStreamingRpc_ManualWriting) {
109   PW_NANOPB_TEST_METHOD_CONTEXT(test::TestService, TestStreamRpc, 3) context;
110 
111   ASSERT_EQ(3u, context.responses().max_size());
112 
113   auto writer = context.writer();
114 
115   writer.Write({.chunk = {}, .number = 3});
116   writer.Write({.chunk = {}, .number = 6});
117   writer.Write({.chunk = {}, .number = 9});
118 
119   EXPECT_FALSE(context.done());
120 
121   writer.Finish(Status::Cancelled());
122   ASSERT_TRUE(context.done());
123   EXPECT_EQ(Status::Cancelled(), context.status());
124 
125   ASSERT_EQ(3u, context.responses().size());
126   ASSERT_EQ(3u, context.total_responses());
127 
128   EXPECT_EQ(context.responses()[0].number, 3u);
129   EXPECT_EQ(context.responses()[1].number, 6u);
130   EXPECT_EQ(context.responses()[2].number, 9u);
131 }
132 
133 using TestServiceClient = test::nanopb::TestServiceClient;
134 using internal::TestServerStreamingResponseHandler;
135 using internal::TestUnaryResponseHandler;
136 
TEST(NanopbCodegen,Client_InvokesUnaryRpcWithCallback)137 TEST(NanopbCodegen, Client_InvokesUnaryRpcWithCallback) {
138   constexpr uint32_t service_id = internal::Hash("pw.rpc.test.TestService");
139   constexpr uint32_t method_id = internal::Hash("TestRpc");
140 
141   ClientContextForTest<128, 128, 99, service_id, method_id> context;
142   TestUnaryResponseHandler<pw_rpc_test_TestResponse> handler;
143 
144   auto call = TestServiceClient::TestRpc(
145       context.channel(), {.integer = 123, .status_code = 0}, handler);
146   EXPECT_EQ(context.output().packet_count(), 1u);
147   auto packet = context.output().sent_packet();
148   EXPECT_EQ(packet.channel_id(), context.channel().id());
149   EXPECT_EQ(packet.service_id(), service_id);
150   EXPECT_EQ(packet.method_id(), method_id);
151   PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
152   EXPECT_EQ(sent_proto.integer, 123);
153 
154   PW_ENCODE_PB(pw_rpc_test_TestResponse, response, .value = 42);
155   context.SendResponse(OkStatus(), response);
156   ASSERT_EQ(handler.responses_received(), 1u);
157   EXPECT_EQ(handler.last_status(), OkStatus());
158   EXPECT_EQ(handler.last_response().value, 42);
159 }
160 
TEST(NanopbCodegen,Client_InvokesServerStreamingRpcWithCallback)161 TEST(NanopbCodegen, Client_InvokesServerStreamingRpcWithCallback) {
162   constexpr uint32_t service_id = internal::Hash("pw.rpc.test.TestService");
163   constexpr uint32_t method_id = internal::Hash("TestStreamRpc");
164 
165   ClientContextForTest<128, 128, 99, service_id, method_id> context;
166   TestServerStreamingResponseHandler<pw_rpc_test_TestStreamResponse> handler;
167 
168   auto call = TestServiceClient::TestStreamRpc(
169       context.channel(), {.integer = 123, .status_code = 0}, handler);
170   EXPECT_EQ(context.output().packet_count(), 1u);
171   auto packet = context.output().sent_packet();
172   EXPECT_EQ(packet.channel_id(), context.channel().id());
173   EXPECT_EQ(packet.service_id(), service_id);
174   EXPECT_EQ(packet.method_id(), method_id);
175   PW_DECODE_PB(pw_rpc_test_TestRequest, sent_proto, packet.payload());
176   EXPECT_EQ(sent_proto.integer, 123);
177 
178   PW_ENCODE_PB(
179       pw_rpc_test_TestStreamResponse, response, .chunk = {}, .number = 11u);
180   context.SendResponse(OkStatus(), response);
181   ASSERT_EQ(handler.responses_received(), 1u);
182   EXPECT_EQ(handler.last_response().number, 11u);
183 
184   context.SendPacket(internal::PacketType::SERVER_STREAM_END,
185                      Status::NotFound());
186   EXPECT_FALSE(handler.active());
187   EXPECT_EQ(handler.status(), Status::NotFound());
188 }
189 
190 }  // namespace
191 }  // namespace pw::rpc
192