1 // Copyright 2022 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/pwpb/client_server_testing_threaded.h"
17 #include "pw_rpc_test_protos/test.rpc.pwpb.h"
18 #include "pw_sync/binary_semaphore.h"
19 #include "pw_thread/test_threads.h"
20
21 namespace pw::rpc {
22 namespace {
23
24 namespace TestRequest = ::pw::rpc::test::pwpb::TestRequest;
25 namespace TestResponse = ::pw::rpc::test::pwpb::TestResponse;
26 namespace TestStreamResponse = ::pw::rpc::test::pwpb::TestStreamResponse;
27
28 } // namespace
29
30 namespace test {
31
32 using GeneratedService = ::pw::rpc::test::pw_rpc::pwpb::TestService;
33
34 class TestService final : public GeneratedService::Service<TestService> {
35 public:
TestUnaryRpc(const TestRequest::Message & request,TestResponse::Message & response)36 Status TestUnaryRpc(const TestRequest::Message& request,
37 TestResponse::Message& response) {
38 response.value = request.integer + 1;
39 return static_cast<Status::Code>(request.status_code);
40 }
41
TestAnotherUnaryRpc(const TestRequest::Message &,PwpbUnaryResponder<TestResponse::Message> &)42 void TestAnotherUnaryRpc(const TestRequest::Message&,
43 PwpbUnaryResponder<TestResponse::Message>&) {}
44
TestServerStreamRpc(const TestRequest::Message &,ServerWriter<TestStreamResponse::Message> &)45 static void TestServerStreamRpc(const TestRequest::Message&,
46 ServerWriter<TestStreamResponse::Message>&) {}
47
TestClientStreamRpc(ServerReader<TestRequest::Message,TestStreamResponse::Message> &)48 void TestClientStreamRpc(
49 ServerReader<TestRequest::Message, TestStreamResponse::Message>&) {}
50
TestBidirectionalStreamRpc(ServerReaderWriter<TestRequest::Message,TestStreamResponse::Message> &)51 void TestBidirectionalStreamRpc(
52 ServerReaderWriter<TestRequest::Message, TestStreamResponse::Message>&) {}
53 };
54
55 } // namespace test
56
57 namespace {
58
59 class RpcCaller {
60 public:
BlockOnResponse(uint32_t i,Client & client,uint32_t channel_id)61 void BlockOnResponse(uint32_t i, Client& client, uint32_t channel_id) {
62 TestRequest::Message request{.integer = i,
63 .status_code = OkStatus().code()};
64 auto call = test::GeneratedService::TestUnaryRpc(
65 client,
66 channel_id,
67 request,
68 [this](const TestResponse::Message&, Status) { semaphore_.release(); },
69 [](Status) {});
70
71 semaphore_.acquire();
72 }
73
74 private:
75 pw::sync::BinarySemaphore semaphore_;
76 };
77
TEST(PwpbClientServerTestContextThreaded,ReceivesUnaryRpcReponseThreaded)78 TEST(PwpbClientServerTestContextThreaded, ReceivesUnaryRpcReponseThreaded) {
79 PwpbClientServerTestContextThreaded<> ctx(thread::test::TestOptionsThread0());
80 test::TestService service;
81 ctx.server().RegisterService(service);
82
83 RpcCaller caller;
84 constexpr auto value = 1;
85 caller.BlockOnResponse(value, ctx.client(), ctx.channel().id());
86
87 const auto request =
88 ctx.request<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(0);
89 const auto response =
90 ctx.response<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(0);
91
92 EXPECT_EQ(value, request.integer);
93 EXPECT_EQ(value + 1, response.value);
94 }
95
TEST(PwpbClientServerTestContextThreaded,ReceivesMultipleReponsesThreaded)96 TEST(PwpbClientServerTestContextThreaded, ReceivesMultipleReponsesThreaded) {
97 PwpbClientServerTestContextThreaded<> ctx(thread::test::TestOptionsThread0());
98 test::TestService service;
99 ctx.server().RegisterService(service);
100
101 RpcCaller caller;
102 constexpr auto value1 = 1;
103 constexpr auto value2 = 2;
104 caller.BlockOnResponse(value1, ctx.client(), ctx.channel().id());
105 caller.BlockOnResponse(value2, ctx.client(), ctx.channel().id());
106
107 const auto request1 =
108 ctx.request<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(0);
109 const auto request2 =
110 ctx.request<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(1);
111 const auto response1 =
112 ctx.response<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(0);
113 const auto response2 =
114 ctx.response<test::pw_rpc::pwpb::TestService::TestUnaryRpc>(1);
115
116 EXPECT_EQ(value1, request1.integer);
117 EXPECT_EQ(value2, request2.integer);
118 EXPECT_EQ(value1 + 1, response1.value);
119 EXPECT_EQ(value2 + 1, response2.value);
120 }
121
122 } // namespace
123 } // namespace pw::rpc
124