• 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 "pw_rpc/internal/raw_method_union.h"
16 
17 #include <array>
18 
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"
27 
28 namespace pw::rpc::internal {
29 namespace {
30 
31 template <typename Implementation>
32 class FakeGeneratedService : public Service {
33  public:
FakeGeneratedService(uint32_t id)34   constexpr FakeGeneratedService(uint32_t id) : Service(id, kMethods) {}
35 
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),
41   };
42 };
43 
44 struct {
45   int64_t integer;
46   uint32_t status_code;
47 } last_request;
48 RawServerWriter last_writer;
49 
50 class FakeGeneratedServiceImpl
51     : public FakeGeneratedService<FakeGeneratedServiceImpl> {
52  public:
FakeGeneratedServiceImpl(uint32_t id)53   FakeGeneratedServiceImpl(uint32_t id) : FakeGeneratedService(id) {}
54 
DoNothing(ServerContext &,ConstByteSpan,ByteSpan)55   StatusWithSize DoNothing(ServerContext&, ConstByteSpan, ByteSpan) {
56     return StatusWithSize::Unknown();
57   }
58 
AddFive(ServerContext &,ConstByteSpan request,ByteSpan response)59   StatusWithSize AddFive(ServerContext&,
60                          ConstByteSpan request,
61                          ByteSpan response) {
62     DecodeRawTestRequest(request);
63 
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);
69 
70     return StatusWithSize::Unauthenticated(payload.size());
71   }
72 
StartStream(ServerContext &,ConstByteSpan request,RawServerWriter & writer)73   void StartStream(ServerContext&,
74                    ConstByteSpan request,
75                    RawServerWriter& writer) {
76     DecodeRawTestRequest(request);
77     last_writer = std::move(writer);
78   }
79 
80  private:
DecodeRawTestRequest(ConstByteSpan request)81   void DecodeRawTestRequest(ConstByteSpan request) {
82     protobuf::Decoder decoder(request);
83 
84     while (decoder.Next().ok()) {
85       test::TestRequest::Fields field =
86           static_cast<test::TestRequest::Fields>(decoder.FieldNumber());
87 
88       switch (field) {
89         case test::TestRequest::Fields::INTEGER:
90           decoder.ReadInt64(&last_request.integer);
91           break;
92         case test::TestRequest::Fields::STATUS_CODE:
93           decoder.ReadUint32(&last_request.status_code);
94           break;
95       }
96     }
97   }
98 };
99 
TEST(RawMethodUnion,InvokesUnary)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);
106 
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()));
111 
112   EXPECT_EQ(last_request.integer, 456);
113   EXPECT_EQ(last_request.status_code, 7u);
114 
115   const Packet& response = context.output().sent_packet();
116   EXPECT_EQ(response.status(), Status::Unauthenticated());
117 
118   protobuf::Decoder decoder(response.payload());
119   ASSERT_TRUE(decoder.Next().ok());
120   int64_t value;
121   EXPECT_EQ(decoder.ReadInt64(&value), OkStatus());
122   EXPECT_EQ(value, 461);
123 }
124 
TEST(RawMethodUnion,InvokesServerStreaming)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);
131 
132   const Method& method =
133       std::get<2>(FakeGeneratedServiceImpl::kMethods).method();
134   ServerContextForTest<FakeGeneratedServiceImpl> context(method);
135 
136   method.Invoke(context.get(), context.packet(encoder.Encode().value()));
137 
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   EXPECT_EQ(OkStatus(), last_writer.Finish());
143 }
144 
145 }  // namespace
146 }  // namespace pw::rpc::internal
147