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/base_server_writer.h"
16
17 #include <algorithm>
18 #include <array>
19 #include <cstdint>
20 #include <cstring>
21
22 #include "gtest/gtest.h"
23 #include "pw_rpc/internal/test_method.h"
24 #include "pw_rpc/server_context.h"
25 #include "pw_rpc/service.h"
26 #include "pw_rpc_private/internal_test_utils.h"
27
28 namespace pw::rpc {
29
30 class TestService : public Service {
31 public:
TestService(uint32_t id)32 constexpr TestService(uint32_t id) : Service(id, method) {}
33
34 static constexpr internal::TestMethodUnion method = internal::TestMethod(8);
35 };
36
37 namespace internal {
38 namespace {
39
40 using std::byte;
41
TEST(BaseServerWriter,ConstructWithContext_StartsOpen)42 TEST(BaseServerWriter, ConstructWithContext_StartsOpen) {
43 ServerContextForTest<TestService> context(TestService::method.method());
44
45 BaseServerWriter writer(context.get());
46
47 EXPECT_TRUE(writer.open());
48 }
49
TEST(BaseServerWriter,Move_ClosesOriginal)50 TEST(BaseServerWriter, Move_ClosesOriginal) {
51 ServerContextForTest<TestService> context(TestService::method.method());
52
53 BaseServerWriter moved(context.get());
54 BaseServerWriter writer(std::move(moved));
55
56 #ifndef __clang_analyzer__
57 EXPECT_FALSE(moved.open());
58 #endif // ignore use-after-move
59 EXPECT_TRUE(writer.open());
60 }
61
62 class FakeServerWriter : public BaseServerWriter {
63 public:
FakeServerWriter(ServerCall & context)64 FakeServerWriter(ServerCall& context) : BaseServerWriter(context) {}
65
66 constexpr FakeServerWriter() = default;
67
Write(std::span<const byte> response)68 Status Write(std::span<const byte> response) {
69 std::span buffer = AcquirePayloadBuffer();
70 std::memcpy(buffer.data(),
71 response.data(),
72 std::min(buffer.size(), response.size()));
73 return ReleasePayloadBuffer(buffer.first(response.size()));
74 }
75
PayloadBuffer()76 ByteSpan PayloadBuffer() { return AcquirePayloadBuffer(); }
output_buffer()77 const Channel::OutputBuffer& output_buffer() { return buffer(); }
78 };
79
TEST(ServerWriter,DefaultConstruct_Closed)80 TEST(ServerWriter, DefaultConstruct_Closed) {
81 FakeServerWriter writer;
82
83 EXPECT_FALSE(writer.open());
84 }
85
TEST(ServerWriter,Construct_RegistersWithServer)86 TEST(ServerWriter, Construct_RegistersWithServer) {
87 ServerContextForTest<TestService> context(TestService::method.method());
88 FakeServerWriter writer(context.get());
89
90 auto& writers = context.server().writers();
91 EXPECT_FALSE(writers.empty());
92 auto it = std::find_if(
93 writers.begin(), writers.end(), [&](auto& w) { return &w == &writer; });
94 ASSERT_NE(it, writers.end());
95 }
96
TEST(ServerWriter,Destruct_RemovesFromServer)97 TEST(ServerWriter, Destruct_RemovesFromServer) {
98 ServerContextForTest<TestService> context(TestService::method.method());
99 { FakeServerWriter writer(context.get()); }
100
101 auto& writers = context.server().writers();
102 EXPECT_TRUE(writers.empty());
103 }
104
TEST(ServerWriter,Finish_RemovesFromServer)105 TEST(ServerWriter, Finish_RemovesFromServer) {
106 ServerContextForTest<TestService> context(TestService::method.method());
107 FakeServerWriter writer(context.get());
108
109 EXPECT_EQ(OkStatus(), writer.Finish());
110
111 auto& writers = context.server().writers();
112 EXPECT_TRUE(writers.empty());
113 }
114
TEST(ServerWriter,Finish_SendsCancellationPacket)115 TEST(ServerWriter, Finish_SendsCancellationPacket) {
116 ServerContextForTest<TestService> context(TestService::method.method());
117 FakeServerWriter writer(context.get());
118
119 EXPECT_EQ(OkStatus(), writer.Finish());
120
121 const Packet& packet = context.output().sent_packet();
122 EXPECT_EQ(packet.type(), PacketType::SERVER_STREAM_END);
123 EXPECT_EQ(packet.channel_id(), context.channel_id());
124 EXPECT_EQ(packet.service_id(), context.service_id());
125 EXPECT_EQ(packet.method_id(), context.get().method().id());
126 EXPECT_TRUE(packet.payload().empty());
127 EXPECT_EQ(packet.status(), OkStatus());
128 }
129
TEST(ServerWriter,Finish_ReturnsStatusFromChannelSend)130 TEST(ServerWriter, Finish_ReturnsStatusFromChannelSend) {
131 ServerContextForTest<TestService> context(TestService::method.method());
132 FakeServerWriter writer(context.get());
133 context.output().set_send_status(Status::Unauthenticated());
134
135 EXPECT_EQ(Status::Unauthenticated(), writer.Finish());
136 }
137
TEST(ServerWriter,Close)138 TEST(ServerWriter, Close) {
139 ServerContextForTest<TestService> context(TestService::method.method());
140 FakeServerWriter writer(context.get());
141
142 ASSERT_TRUE(writer.open());
143 EXPECT_EQ(OkStatus(), writer.Finish());
144 EXPECT_FALSE(writer.open());
145 EXPECT_EQ(Status::FailedPrecondition(), writer.Finish());
146 }
147
TEST(ServerWriter,Close_ReleasesBuffer)148 TEST(ServerWriter, Close_ReleasesBuffer) {
149 ServerContextForTest<TestService> context(TestService::method.method());
150 FakeServerWriter writer(context.get());
151
152 ASSERT_TRUE(writer.open());
153 auto buffer = writer.PayloadBuffer();
154 buffer[0] = std::byte{0};
155 EXPECT_FALSE(writer.output_buffer().empty());
156 EXPECT_EQ(OkStatus(), writer.Finish());
157 EXPECT_FALSE(writer.open());
158 EXPECT_TRUE(writer.output_buffer().empty());
159 }
160
TEST(ServerWriter,Open_SendsPacketWithPayload)161 TEST(ServerWriter, Open_SendsPacketWithPayload) {
162 ServerContextForTest<TestService> context(TestService::method.method());
163 FakeServerWriter writer(context.get());
164
165 constexpr byte data[] = {byte{0xf0}, byte{0x0d}};
166 ASSERT_EQ(OkStatus(), writer.Write(data));
167
168 byte encoded[64];
169 auto result = context.packet(data).Encode(encoded);
170 ASSERT_EQ(OkStatus(), result.status());
171
172 EXPECT_EQ(result.value().size(), context.output().sent_data().size());
173 EXPECT_EQ(
174 0,
175 std::memcmp(
176 encoded, context.output().sent_data().data(), result.value().size()));
177 }
178
TEST(ServerWriter,Closed_IgnoresFinish)179 TEST(ServerWriter, Closed_IgnoresFinish) {
180 ServerContextForTest<TestService> context(TestService::method.method());
181 FakeServerWriter writer(context.get());
182
183 EXPECT_EQ(OkStatus(), writer.Finish());
184 EXPECT_EQ(Status::FailedPrecondition(), writer.Finish());
185 }
186
187 } // namespace
188 } // namespace internal
189 } // namespace pw::rpc
190