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_protobuf/decoder.h"
17 #include "pw_rpc/internal/hash.h"
18 #include "pw_rpc/raw_test_method_context.h"
19 #include "pw_rpc_test_protos/test.pwpb.h"
20 #include "pw_rpc_test_protos/test.raw_rpc.pb.h"
21
22 namespace pw::rpc {
23 namespace test {
24
25 class TestService final : public generated::TestService<TestService> {
26 public:
TestRpc(ServerContext &,ConstByteSpan request,ByteSpan response)27 static StatusWithSize TestRpc(ServerContext&,
28 ConstByteSpan request,
29 ByteSpan response) {
30 int64_t integer;
31 Status status;
32
33 if (!DecodeRequest(request, integer, status)) {
34 return StatusWithSize::DataLoss();
35 }
36
37 protobuf::NestedEncoder encoder(response);
38 TestResponse::Encoder test_response(&encoder);
39 test_response.WriteValue(integer + 1);
40
41 return StatusWithSize(status, encoder.Encode().value().size());
42 }
43
TestStreamRpc(ServerContext &,ConstByteSpan request,RawServerWriter & writer)44 void TestStreamRpc(ServerContext&,
45 ConstByteSpan request,
46 RawServerWriter& writer) {
47 int64_t integer;
48 Status status;
49
50 ASSERT_TRUE(DecodeRequest(request, integer, status));
51 for (int i = 0; i < integer; ++i) {
52 ByteSpan buffer = writer.PayloadBuffer();
53 protobuf::NestedEncoder encoder(buffer);
54 TestStreamResponse::Encoder test_stream_response(&encoder);
55 test_stream_response.WriteNumber(i);
56 writer.Write(encoder.Encode().value());
57 }
58
59 writer.Finish(status);
60 }
61
62 private:
DecodeRequest(ConstByteSpan request,int64_t & integer,Status & status)63 static bool DecodeRequest(ConstByteSpan request,
64 int64_t& integer,
65 Status& status) {
66 protobuf::Decoder decoder(request);
67 Status decode_status;
68 bool has_integer = false;
69 bool has_status = false;
70
71 while (decoder.Next().ok()) {
72 switch (static_cast<TestRequest::Fields>(decoder.FieldNumber())) {
73 case TestRequest::Fields::INTEGER:
74 decode_status = decoder.ReadInt64(&integer);
75 EXPECT_EQ(OkStatus(), decode_status);
76 has_integer = decode_status.ok();
77 break;
78 case TestRequest::Fields::STATUS_CODE: {
79 uint32_t status_code;
80 decode_status = decoder.ReadUint32(&status_code);
81 EXPECT_EQ(OkStatus(), decode_status);
82 has_status = decode_status.ok();
83 status = static_cast<Status::Code>(status_code);
84 break;
85 }
86 }
87 }
88 EXPECT_TRUE(has_integer);
89 EXPECT_TRUE(has_status);
90 return has_integer && has_status;
91 }
92 };
93
94 } // namespace test
95
96 namespace {
97
TEST(RawCodegen,CompilesProperly)98 TEST(RawCodegen, CompilesProperly) {
99 test::TestService service;
100 EXPECT_EQ(service.id(), internal::Hash("pw.rpc.test.TestService"));
101 EXPECT_STREQ(service.name(), "TestService");
102 }
103
TEST(RawCodegen,Server_InvokeUnaryRpc)104 TEST(RawCodegen, Server_InvokeUnaryRpc) {
105 PW_RAW_TEST_METHOD_CONTEXT(test::TestService, TestRpc) context;
106
107 std::byte buffer[64];
108 protobuf::NestedEncoder encoder(buffer);
109 test::TestRequest::Encoder test_request(&encoder);
110 test_request.WriteInteger(123);
111 test_request.WriteStatusCode(OkStatus().code());
112
113 auto sws = context.call(encoder.Encode().value());
114 EXPECT_EQ(OkStatus(), sws.status());
115
116 protobuf::Decoder decoder(context.response());
117
118 while (decoder.Next().ok()) {
119 switch (static_cast<test::TestResponse::Fields>(decoder.FieldNumber())) {
120 case test::TestResponse::Fields::VALUE: {
121 int32_t value;
122 decoder.ReadInt32(&value);
123 EXPECT_EQ(value, 124);
124 break;
125 }
126 }
127 }
128 }
129
TEST(RawCodegen,Server_InvokeServerStreamingRpc)130 TEST(RawCodegen, Server_InvokeServerStreamingRpc) {
131 PW_RAW_TEST_METHOD_CONTEXT(test::TestService, TestStreamRpc) context;
132
133 std::byte buffer[64];
134 protobuf::NestedEncoder encoder(buffer);
135 test::TestRequest::Encoder test_request(&encoder);
136 test_request.WriteInteger(5);
137 test_request.WriteStatusCode(Status::Unauthenticated().code());
138
139 context.call(encoder.Encode().value());
140 EXPECT_TRUE(context.done());
141 EXPECT_EQ(Status::Unauthenticated(), context.status());
142 EXPECT_EQ(context.total_responses(), 5u);
143
144 protobuf::Decoder decoder(context.responses().back());
145 while (decoder.Next().ok()) {
146 switch (
147 static_cast<test::TestStreamResponse::Fields>(decoder.FieldNumber())) {
148 case test::TestStreamResponse::Fields::NUMBER: {
149 int32_t value;
150 decoder.ReadInt32(&value);
151 EXPECT_EQ(value, 4);
152 break;
153 }
154 case test::TestStreamResponse::Fields::CHUNK:
155 FAIL();
156 break;
157 }
158 }
159 }
160
161 } // namespace
162 } // namespace pw::rpc
163