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