1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_rpc/internal/raw_method_union.h"
19 #include "gtest/gtest.h"
20 #include "pw_bytes/array.h"
21 #include "pw_protobuf/decoder.h"
22 #include "pw_protobuf/encoder.h"
23 #include "pw_rpc/server_context.h"
24 #include "pw_rpc/service.h"
25 #include "pw_rpc_private/internal_test_utils.h"
26 #include "pw_rpc_test_protos/test.pwpb.h"
28 namespace pw::rpc::internal {
31 template <typename Implementation>
32 class FakeGeneratedService : public Service {
34 constexpr FakeGeneratedService(uint32_t id) : Service(id, kMethods) {}
36 static constexpr std::array<RawMethodUnion, 3> kMethods = {
37 GetRawMethodFor<&Implementation::DoNothing, MethodType::kUnary>(10u),
38 GetRawMethodFor<&Implementation::AddFive, MethodType::kUnary>(11u),
39 GetRawMethodFor<&Implementation::StartStream,
40 MethodType::kServerStreaming>(12u),
48 RawServerWriter last_writer;
50 class FakeGeneratedServiceImpl
51 : public FakeGeneratedService<FakeGeneratedServiceImpl> {
53 FakeGeneratedServiceImpl(uint32_t id) : FakeGeneratedService(id) {}
55 StatusWithSize DoNothing(ServerContext&, ConstByteSpan, ByteSpan) {
56 return StatusWithSize::Unknown();
59 StatusWithSize AddFive(ServerContext&,
60 ConstByteSpan request,
62 DecodeRawTestRequest(request);
64 protobuf::NestedEncoder encoder(response);
65 test::TestResponse::Encoder test_response(&encoder);
66 test_response.WriteValue(last_request.integer + 5);
67 ConstByteSpan payload;
68 encoder.Encode(&payload);
70 return StatusWithSize::Unauthenticated(payload.size());
73 void StartStream(ServerContext&,
74 ConstByteSpan request,
75 RawServerWriter& writer) {
76 DecodeRawTestRequest(request);
77 last_writer = std::move(writer);
81 void DecodeRawTestRequest(ConstByteSpan request) {
82 protobuf::Decoder decoder(request);
84 while (decoder.Next().ok()) {
85 test::TestRequest::Fields field =
86 static_cast<test::TestRequest::Fields>(decoder.FieldNumber());
89 case test::TestRequest::Fields::INTEGER:
90 decoder.ReadInt64(&last_request.integer);
92 case test::TestRequest::Fields::STATUS_CODE:
93 decoder.ReadUint32(&last_request.status_code);
100 TEST(RawMethodUnion, InvokesUnary) {
101 std::byte buffer[16];
102 protobuf::NestedEncoder encoder(buffer);
103 test::TestRequest::Encoder test_request(&encoder);
104 test_request.WriteInteger(456);
105 test_request.WriteStatusCode(7);
107 const Method& method =
108 std::get<1>(FakeGeneratedServiceImpl::kMethods).method();
109 ServerContextForTest<FakeGeneratedServiceImpl> context(method);
110 method.Invoke(context.get(), context.packet(encoder.Encode().value()));
112 EXPECT_EQ(last_request.integer, 456);
113 EXPECT_EQ(last_request.status_code, 7u);
115 const Packet& response = context.output().sent_packet();
116 EXPECT_EQ(response.status(), Status::Unauthenticated());
118 protobuf::Decoder decoder(response.payload());
119 ASSERT_TRUE(decoder.Next().ok());
121 EXPECT_EQ(decoder.ReadInt64(&value), OkStatus());
122 EXPECT_EQ(value, 461);
125 TEST(RawMethodUnion, InvokesServerStreaming) {
126 std::byte buffer[16];
127 protobuf::NestedEncoder encoder(buffer);
128 test::TestRequest::Encoder test_request(&encoder);
129 test_request.WriteInteger(777);
130 test_request.WriteStatusCode(2);
132 const Method& method =
133 std::get<2>(FakeGeneratedServiceImpl::kMethods).method();
134 ServerContextForTest<FakeGeneratedServiceImpl> context(method);
136 method.Invoke(context.get(), context.packet(encoder.Encode().value()));
138 EXPECT_EQ(0u, context.output().packet_count());
139 EXPECT_EQ(777, last_request.integer);
140 EXPECT_EQ(2u, last_request.status_code);
141 EXPECT_TRUE(last_writer.open());
142 last_writer.Finish();
146 } // namespace pw::rpc::internal