blob: ac8978d352b5124c23df035610fafd083021b38c [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/credit_based_flow_control_rx_engine.h"
#include <gtest/gtest.h>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fragmenter.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
namespace bt::l2cap::internal {
namespace {
using Engine = CreditBasedFlowControlRxEngine;
class CreditBasedFlowControlRxEngineTest : public ::testing::Test {
protected:
static constexpr hci_spec::ConnectionHandle kTestHandle = 0x0001;
static constexpr ChannelId kTestChannelId = 0x0001;
Engine& engine() { return *engine_; }
size_t failure_callback_count() { return failure_callback_count_; }
PDU ToPdu(const ByteBuffer& buffer) {
return Fragmenter(kTestHandle)
.BuildFrame(kTestChannelId, buffer, FrameCheckSequenceOption::kNoFcs);
}
ByteBufferPtr ProcessPayload(const ByteBuffer& buffer) {
return engine().ProcessPdu(ToPdu(buffer));
}
private:
size_t failure_callback_count_ = 0;
std::unique_ptr<Engine> engine_ =
std::make_unique<Engine>([this] { ++failure_callback_count_; });
};
TEST_F(CreditBasedFlowControlRxEngineTest, SmallUnsegmentedSdu) {
// clang-format off
const StaticByteBuffer payload(
// SDU size field (LE u16)
4, 0,
// Payload
't', 'e', 's', 't'
);
// clang-format on
const ByteBufferPtr sdu = ProcessPayload(payload);
ASSERT_TRUE(sdu);
EXPECT_TRUE(ContainersEqual(StaticByteBuffer('t', 'e', 's', 't'), *sdu));
EXPECT_EQ(0u, failure_callback_count());
}
TEST_F(CreditBasedFlowControlRxEngineTest, LargeUnsegmentedSdu) {
// clang-format off
const StaticByteBuffer payload(
// SDU size field (LE u16)
58, 0,
// Payload
'L', 'o', 'r', 'e', 'm', ' ', 'i', 'p', 's', 'u', 'm', ' ', 'd', 'o', 'l',
'o', 'r', ' ', 's', 'i', 't', ' ', 'a', 'm', 'e', 't', ',', ' ', 'c', 'o',
'n', 's', 'e', 'c', 't', 'e', 't', 'u', 'r', ' ', 'a', 'd', 'i', 'p', 'i',
's', 'c', 'i', 'n', 'g', ' ', 'e', 'l', 'i', 't', '.', ' ', 'S'
);
// clang-format on
const ByteBufferPtr sdu = ProcessPayload(payload);
ASSERT_TRUE(sdu);
EXPECT_TRUE(ContainersEqual(payload.view(2), *sdu));
EXPECT_EQ(0u, failure_callback_count());
}
TEST_F(CreditBasedFlowControlRxEngineTest, SduSegmentedIntoManySmallPdus) {
// clang-format off
EXPECT_FALSE(ProcessPayload(StaticByteBuffer(
// SDU size field (LE u16)
16, 0,
// First four bytes of payload
't', 'e', 's', 't'
)));
// clang-format on
EXPECT_FALSE(ProcessPayload(StaticByteBuffer('i', 'n', 'g', ' ')));
EXPECT_FALSE(ProcessPayload(StaticByteBuffer('f', 'o', 'r', ' ')));
const ByteBufferPtr sdu =
ProcessPayload(StaticByteBuffer('b', 'u', 'g', 's'));
// clang-format off
StaticByteBuffer expected(
't', 'e', 's', 't', 'i', 'n', 'g', ' ',
'f', 'o', 'r', ' ', 'b', 'u', 'g', 's'
);
// clang-format on
ASSERT_TRUE(sdu);
EXPECT_TRUE(ContainersEqual(expected, *sdu));
EXPECT_EQ(0u, failure_callback_count());
}
TEST_F(CreditBasedFlowControlRxEngineTest, FailSduSmallerThanPayload) {
// clang-format off
const StaticByteBuffer payload(
// SDU size field (LE u16)
4, 0,
// Payload
'f', 'a', 'i', 'l', 'i', 'u', 'r', 'e'
);
// clang-format on
EXPECT_FALSE(ProcessPayload(payload));
EXPECT_EQ(1u, failure_callback_count());
}
TEST_F(CreditBasedFlowControlRxEngineTest, FailSduSmallerThanPayloadSegmented) {
// clang-format off
const StaticByteBuffer payload(
// SDU size field (LE u16)
5, 0,
// Payload
'f', 'a', 'i', 'l'
);
// clang-format on
EXPECT_FALSE(ProcessPayload(payload));
EXPECT_EQ(0u, failure_callback_count());
EXPECT_FALSE(ProcessPayload(StaticByteBuffer('i', 'u', 'r', 'e')));
EXPECT_EQ(1u, failure_callback_count());
}
TEST_F(CreditBasedFlowControlRxEngineTest, InitialFrameMissingSduSize) {
const ByteBufferPtr sdu = ProcessPayload(StaticByteBuffer(0));
EXPECT_FALSE(sdu);
EXPECT_EQ(1u, failure_callback_count());
}
} // namespace
} // namespace bt::l2cap::internal