1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker // clang-format off
16*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/log_config.h" // PW_LOG_* macros must be first.
17*61c4878aSAndroid Build Coastguard Worker
18*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/fake_channel_output.h"
19*61c4878aSAndroid Build Coastguard Worker // clang-format on
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_result/result.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/internal/packet.h"
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker namespace pw::rpc::internal::test {
27*61c4878aSAndroid Build Coastguard Worker
clear()28*61c4878aSAndroid Build Coastguard Worker void FakeChannelOutput::clear() {
29*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
30*61c4878aSAndroid Build Coastguard Worker payloads_.clear();
31*61c4878aSAndroid Build Coastguard Worker packets_.clear();
32*61c4878aSAndroid Build Coastguard Worker send_status_ = OkStatus();
33*61c4878aSAndroid Build Coastguard Worker return_after_packet_count_ = -1;
34*61c4878aSAndroid Build Coastguard Worker }
35*61c4878aSAndroid Build Coastguard Worker
HandlePacket(span<const std::byte> buffer)36*61c4878aSAndroid Build Coastguard Worker Status FakeChannelOutput::HandlePacket(span<const std::byte> buffer) {
37*61c4878aSAndroid Build Coastguard Worker // If the buffer is empty, this is just releasing an unused buffer.
38*61c4878aSAndroid Build Coastguard Worker if (buffer.empty()) {
39*61c4878aSAndroid Build Coastguard Worker return OkStatus();
40*61c4878aSAndroid Build Coastguard Worker }
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker if (return_after_packet_count_ == 0) {
43*61c4878aSAndroid Build Coastguard Worker return send_status_;
44*61c4878aSAndroid Build Coastguard Worker }
45*61c4878aSAndroid Build Coastguard Worker if (return_after_packet_count_ > 0 &&
46*61c4878aSAndroid Build Coastguard Worker return_after_packet_count_ == static_cast<int>(packets_.size())) {
47*61c4878aSAndroid Build Coastguard Worker // Disable behavior.
48*61c4878aSAndroid Build Coastguard Worker return_after_packet_count_ = -1;
49*61c4878aSAndroid Build Coastguard Worker return send_status_;
50*61c4878aSAndroid Build Coastguard Worker }
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker Result<Packet> result = Packet::FromBuffer(buffer);
53*61c4878aSAndroid Build Coastguard Worker PW_CHECK_OK(result.status());
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker PW_CHECK(!packets_.full(),
56*61c4878aSAndroid Build Coastguard Worker "Attempted to store more than %u packets. Increase the kMaxPackets "
57*61c4878aSAndroid Build Coastguard Worker "template arg to store more packets.",
58*61c4878aSAndroid Build Coastguard Worker static_cast<unsigned>(packets_.size()));
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard Worker packets_.push_back(*result);
61*61c4878aSAndroid Build Coastguard Worker Packet& packet = packets_.back();
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker CopyPayloadToBuffer(packet);
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker switch (packet.type()) {
66*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::REQUEST:
67*61c4878aSAndroid Build Coastguard Worker return OkStatus();
68*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::RESPONSE:
69*61c4878aSAndroid Build Coastguard Worker total_response_packets_ += 1;
70*61c4878aSAndroid Build Coastguard Worker return OkStatus();
71*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::CLIENT_STREAM:
72*61c4878aSAndroid Build Coastguard Worker return OkStatus();
73*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::CLIENT_ERROR:
74*61c4878aSAndroid Build Coastguard Worker PW_LOG_WARN("FakeChannelOutput received client error: %s",
75*61c4878aSAndroid Build Coastguard Worker packet.status().str());
76*61c4878aSAndroid Build Coastguard Worker return OkStatus();
77*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::SERVER_ERROR:
78*61c4878aSAndroid Build Coastguard Worker PW_LOG_WARN("FakeChannelOutput received server error: %s",
79*61c4878aSAndroid Build Coastguard Worker packet.status().str());
80*61c4878aSAndroid Build Coastguard Worker return OkStatus();
81*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::SERVER_STREAM:
82*61c4878aSAndroid Build Coastguard Worker case pwpb::PacketType::CLIENT_REQUEST_COMPLETION:
83*61c4878aSAndroid Build Coastguard Worker return OkStatus();
84*61c4878aSAndroid Build Coastguard Worker }
85*61c4878aSAndroid Build Coastguard Worker PW_CRASH("Unhandled PacketType %d", static_cast<int>(result.value().type()));
86*61c4878aSAndroid Build Coastguard Worker }
87*61c4878aSAndroid Build Coastguard Worker
CopyPayloadToBuffer(Packet & packet)88*61c4878aSAndroid Build Coastguard Worker void FakeChannelOutput::CopyPayloadToBuffer(Packet& packet) {
89*61c4878aSAndroid Build Coastguard Worker const ConstByteSpan& payload = packet.payload();
90*61c4878aSAndroid Build Coastguard Worker if (payload.empty()) {
91*61c4878aSAndroid Build Coastguard Worker return;
92*61c4878aSAndroid Build Coastguard Worker }
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker const size_t available_bytes = payloads_.max_size() - payloads_.size();
95*61c4878aSAndroid Build Coastguard Worker PW_CHECK_UINT_GE(available_bytes,
96*61c4878aSAndroid Build Coastguard Worker payload.size(),
97*61c4878aSAndroid Build Coastguard Worker "Ran out of payload buffer space. Increase "
98*61c4878aSAndroid Build Coastguard Worker "kPayloadBufferSizeBytes (%u) or use smaller payloads.",
99*61c4878aSAndroid Build Coastguard Worker static_cast<unsigned>(payloads_.max_size()));
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard Worker const size_t start = payloads_.size();
102*61c4878aSAndroid Build Coastguard Worker payloads_.resize(payloads_.size() + payload.size());
103*61c4878aSAndroid Build Coastguard Worker std::memcpy(&payloads_[start], payload.data(), payload.size());
104*61c4878aSAndroid Build Coastguard Worker packet.set_payload(span(&payloads_[start], payload.size()));
105*61c4878aSAndroid Build Coastguard Worker }
106*61c4878aSAndroid Build Coastguard Worker
LogPackets() const107*61c4878aSAndroid Build Coastguard Worker void FakeChannelOutput::LogPackets() const {
108*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(mutex_);
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("%u packets have been sent through this FakeChannelOutput",
111*61c4878aSAndroid Build Coastguard Worker static_cast<unsigned>(packets_.size()));
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker for (unsigned i = 0; i < packets_.size(); ++i) {
114*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO("[packet %u/%u]", i + 1, unsigned(packets_.size()));
115*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" type: %u", unsigned(packets_[i].type()));
116*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" channel_id: %u", unsigned(packets_[i].channel_id()));
117*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" service_id: %08x", unsigned(packets_[i].service_id()));
118*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" method_id: %08x", unsigned(packets_[i].method_id()));
119*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" call_id: %u", unsigned(packets_[i].call_id()));
120*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" status: %s", packets_[i].status().str());
121*61c4878aSAndroid Build Coastguard Worker PW_LOG_INFO(" payload: %u B", unsigned(packets_[i].payload().size()));
122*61c4878aSAndroid Build Coastguard Worker }
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker } // namespace pw::rpc::internal::test
126