1 // Copyright 2021 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/fake_channel_output.h"
16
17 #include <array>
18 #include <cstddef>
19 #include <memory>
20
21 #include "pw_rpc/channel.h"
22 #include "pw_rpc/internal/lock.h"
23 #include "pw_rpc/internal/packet.h"
24 #include "pw_unit_test/framework.h"
25
26 namespace pw::rpc::internal::test {
27 namespace {
28
29 constexpr uint32_t kChannelId = 1;
30 constexpr uint32_t kServiceId = 1;
31 constexpr uint32_t kMethodId = 1;
32 constexpr uint32_t kCallId = 0;
33 constexpr std::array<std::byte, 3> kPayload = {
34 std::byte(1), std::byte(2), std::byte(3)};
35
36 class TestFakeChannelOutput final : public FakeChannelOutputBuffer<9, 128> {
37 public:
38 TestFakeChannelOutput() = default;
39
last_response(MethodType type)40 const ConstByteSpan& last_response(MethodType type) {
41 return payloads(type, kChannelId, kServiceId, kMethodId).back();
42 }
43
total_payloads(MethodType type)44 size_t total_payloads(MethodType type) {
45 return payloads(type, kChannelId, kServiceId, kMethodId).size();
46 }
47 };
48
TEST(FakeChannelOutput,SendAndClear)49 TEST(FakeChannelOutput, SendAndClear) {
50 constexpr MethodType type = MethodType::kServerStreaming;
51 TestFakeChannelOutput output;
52 Channel public_channel = Channel::Create<kChannelId>(&output);
53 internal::ChannelBase& channel = public_channel;
54
55 const internal::Packet server_stream_packet(pwpb::PacketType::SERVER_STREAM,
56 kChannelId,
57 kServiceId,
58 kMethodId,
59 kCallId,
60 kPayload);
61 RpcLockGuard lock;
62 ASSERT_EQ(channel.Send(server_stream_packet), OkStatus());
63 ASSERT_EQ(output.last_response(type).size(), kPayload.size());
64 EXPECT_EQ(
65 std::memcmp(
66 output.last_response(type).data(), kPayload.data(), kPayload.size()),
67 0);
68 EXPECT_EQ(output.total_payloads(type), 1u);
69 EXPECT_EQ(output.total_packets(), 1u);
70 EXPECT_FALSE(output.done());
71
72 output.clear();
73 EXPECT_EQ(output.total_payloads(type), 0u);
74 EXPECT_EQ(output.total_packets(), 0u);
75 EXPECT_FALSE(output.done());
76 }
77
TEST(FakeChannelOutput,SendAndFakeFutureResults)78 TEST(FakeChannelOutput, SendAndFakeFutureResults) {
79 constexpr MethodType type = MethodType::kUnary;
80 TestFakeChannelOutput output;
81 Channel public_channel = Channel::Create<kChannelId>(&output);
82 internal::ChannelBase& channel = public_channel;
83
84 const internal::Packet response_packet(pwpb::PacketType::RESPONSE,
85 kChannelId,
86 kServiceId,
87 kMethodId,
88 kCallId,
89 kPayload);
90 RpcLockGuard lock;
91 EXPECT_EQ(channel.Send(response_packet), OkStatus());
92 EXPECT_EQ(output.total_payloads(type), 1u);
93 EXPECT_EQ(output.total_packets(), 1u);
94 EXPECT_TRUE(output.done());
95
96 // Multiple calls will return the same error status.
97 output.set_send_status(Status::Unknown());
98 EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
99 EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
100 EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
101 EXPECT_EQ(output.total_payloads(type), 1u);
102 EXPECT_EQ(output.total_packets(), 1u);
103
104 // Turn off error status behavior.
105 output.set_send_status(OkStatus());
106 EXPECT_EQ(channel.Send(response_packet), OkStatus());
107 EXPECT_EQ(output.total_payloads(type), 2u);
108 EXPECT_EQ(output.total_packets(), 2u);
109
110 const internal::Packet server_stream_packet(pwpb::PacketType::SERVER_STREAM,
111 kChannelId,
112 kServiceId,
113 kMethodId,
114 kCallId,
115 kPayload);
116 EXPECT_EQ(channel.Send(server_stream_packet), OkStatus());
117 ASSERT_EQ(output.last_response(type).size(), kPayload.size());
118 EXPECT_EQ(
119 std::memcmp(
120 output.last_response(type).data(), kPayload.data(), kPayload.size()),
121 0);
122 EXPECT_EQ(output.total_payloads(type), 2u);
123 EXPECT_EQ(output.total_packets(), 3u);
124 EXPECT_TRUE(output.done());
125 }
126
TEST(FakeChannelOutput,SendAndFakeSingleResult)127 TEST(FakeChannelOutput, SendAndFakeSingleResult) {
128 constexpr MethodType type = MethodType::kUnary;
129 TestFakeChannelOutput output;
130 Channel public_channel = Channel::Create<kChannelId>(&output);
131 internal::ChannelBase& channel = public_channel;
132
133 const internal::Packet response_packet(pwpb::PacketType::RESPONSE,
134 kChannelId,
135 kServiceId,
136 kMethodId,
137 kCallId,
138 kPayload);
139 // Multiple calls will return the same error status.
140 const int packet_count_fail = 4;
141 output.set_send_status(Status::Unknown(), packet_count_fail);
142 RpcLockGuard lock;
143
144 for (int i = 0; i < packet_count_fail; ++i) {
145 EXPECT_EQ(channel.Send(response_packet), OkStatus());
146 }
147 EXPECT_EQ(channel.Send(response_packet), Status::Unknown());
148 for (int i = 0; i < packet_count_fail; ++i) {
149 EXPECT_EQ(channel.Send(response_packet), OkStatus());
150 }
151
152 const size_t total_response_packets =
153 static_cast<size_t>(2 * packet_count_fail);
154 EXPECT_EQ(output.total_payloads(type), total_response_packets);
155 EXPECT_EQ(output.total_packets(), total_response_packets);
156
157 // Turn off error status behavior.
158 output.set_send_status(OkStatus());
159 EXPECT_EQ(channel.Send(response_packet), OkStatus());
160 EXPECT_EQ(output.total_payloads(type), total_response_packets + 1);
161 EXPECT_EQ(output.total_packets(), total_response_packets + 1);
162 }
163
TEST(FakeChannelOutput,SendResponseUpdated)164 TEST(FakeChannelOutput, SendResponseUpdated) {
165 TestFakeChannelOutput output;
166 Channel public_channel = Channel::Create<kChannelId>(&output);
167 internal::ChannelBase& channel = public_channel;
168
169 const internal::Packet response_packet(pwpb::PacketType::RESPONSE,
170 kChannelId,
171 kServiceId,
172 kMethodId,
173 kCallId,
174 kPayload);
175 RpcLockGuard lock;
176 ASSERT_EQ(channel.Send(response_packet), OkStatus());
177 ASSERT_EQ(output.last_response(MethodType::kUnary).size(), kPayload.size());
178 EXPECT_EQ(std::memcmp(output.last_response(MethodType::kUnary).data(),
179 kPayload.data(),
180 kPayload.size()),
181 0);
182 EXPECT_EQ(output.total_payloads(MethodType::kUnary), 1u);
183 EXPECT_EQ(output.total_packets(), 1u);
184 EXPECT_TRUE(output.done());
185
186 output.clear();
187 const internal::Packet packet_empty_payload(pwpb::PacketType::RESPONSE,
188 kChannelId,
189 kServiceId,
190 kMethodId,
191 kCallId,
192 {});
193 EXPECT_EQ(channel.Send(packet_empty_payload), OkStatus());
194 EXPECT_EQ(output.last_response(MethodType::kUnary).size(), 0u);
195 EXPECT_EQ(output.total_payloads(MethodType::kUnary), 1u);
196 EXPECT_EQ(output.total_packets(), 1u);
197 EXPECT_TRUE(output.done());
198
199 const internal::Packet server_stream_packet(pwpb::PacketType::SERVER_STREAM,
200 kChannelId,
201 kServiceId,
202 kMethodId,
203 kCallId,
204 kPayload);
205 ASSERT_EQ(channel.Send(server_stream_packet), OkStatus());
206 ASSERT_EQ(output.total_payloads(MethodType::kServerStreaming), 1u);
207 ASSERT_EQ(output.last_response(MethodType::kServerStreaming).size(),
208 kPayload.size());
209 EXPECT_EQ(
210 std::memcmp(output.last_response(MethodType::kServerStreaming).data(),
211 kPayload.data(),
212 kPayload.size()),
213 0);
214 EXPECT_EQ(output.total_payloads(MethodType::kServerStreaming), 1u);
215 EXPECT_EQ(output.total_packets(), 2u);
216 EXPECT_TRUE(output.done());
217 }
218
219 } // namespace
220 } // namespace pw::rpc::internal::test
221