• 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/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