blob: 2beef1e993384fdc7ef4efc09d52886fbd20b016 [file] [log] [blame]
// Copyright 2020 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/low_energy_command_handler.h"
#include <pw_async/fake_dispatcher_fixture.h>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fake_signaling_channel.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
namespace bt::l2cap::internal {
class LowEnergyCommandHandlerTest
: public pw::async::test::FakeDispatcherFixture {
public:
LowEnergyCommandHandlerTest() = default;
~LowEnergyCommandHandlerTest() override = default;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyCommandHandlerTest);
protected:
// TestLoopFixture overrides
void SetUp() override {
signaling_channel_ =
std::make_unique<testing::FakeSignalingChannel>(dispatcher());
command_handler_ = std::make_unique<LowEnergyCommandHandler>(
fake_sig(),
fit::bind_member<&LowEnergyCommandHandlerTest::OnRequestFail>(this));
request_fail_callback_ = nullptr;
failed_requests_ = 0;
}
void TearDown() override {
request_fail_callback_ = nullptr;
signaling_channel_ = nullptr;
command_handler_ = nullptr;
}
testing::FakeSignalingChannel* fake_sig() const {
return signaling_channel_.get();
}
LowEnergyCommandHandler* cmd_handler() const {
return command_handler_.get();
}
size_t failed_requests() const { return failed_requests_; }
void set_request_fail_callback(fit::closure request_fail_callback) {
BT_ASSERT(!request_fail_callback_);
request_fail_callback_ = std::move(request_fail_callback);
}
private:
void OnRequestFail() {
failed_requests_++;
if (request_fail_callback_) {
request_fail_callback_();
}
}
std::unique_ptr<testing::FakeSignalingChannel> signaling_channel_;
std::unique_ptr<LowEnergyCommandHandler> command_handler_;
fit::closure request_fail_callback_;
size_t failed_requests_;
};
TEST_F(LowEnergyCommandHandlerTest, OutboundConnParamUpdateReqRspOk) {
constexpr uint16_t kIntervalMin = 0;
constexpr uint16_t kIntervalMax = 1;
constexpr uint16_t kPeripheralLatency = 2;
constexpr uint16_t kTimeoutMult = 3;
StaticByteBuffer param_update_req(
// Interval Min
LowerBits(kIntervalMin),
UpperBits(kIntervalMin),
// Interval Max
LowerBits(kIntervalMax),
UpperBits(kIntervalMax),
// Peripheral Latency
LowerBits(kPeripheralLatency),
UpperBits(kPeripheralLatency),
// Timeout Multiplier
LowerBits(kTimeoutMult),
UpperBits(kTimeoutMult));
StaticByteBuffer param_update_rsp(
LowerBits(
static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)),
UpperBits(
static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)));
bool cb_called = false;
LowEnergyCommandHandler::ConnectionParameterUpdateResponseCallback rsp_cb =
[&](const LowEnergyCommandHandler::ConnectionParameterUpdateResponse&
rsp) {
cb_called = true;
EXPECT_EQ(SignalingChannel::Status::kSuccess, rsp.status());
EXPECT_EQ(ConnectionParameterUpdateResult::kRejected, rsp.result());
};
EXPECT_OUTBOUND_REQ(
*fake_sig(),
kConnectionParameterUpdateRequest,
param_update_req.view(),
{SignalingChannel::Status::kSuccess, param_update_rsp.view()});
EXPECT_TRUE(
cmd_handler()->SendConnectionParameterUpdateRequest(kIntervalMin,
kIntervalMax,
kPeripheralLatency,
kTimeoutMult,
std::move(rsp_cb)));
RunUntilIdle();
EXPECT_TRUE(cb_called);
}
TEST_F(LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqRspOk) {
constexpr uint16_t kIntervalMin = 0;
constexpr uint16_t kIntervalMax = 1;
constexpr uint16_t kPeripheralLatency = 2;
constexpr uint16_t kTimeoutMult = 3;
StaticByteBuffer param_update_req(
// Interval Min
LowerBits(kIntervalMin),
UpperBits(kIntervalMin),
// Interval Max
LowerBits(kIntervalMax),
UpperBits(kIntervalMax),
// Peripheral Latency
LowerBits(kPeripheralLatency),
UpperBits(kPeripheralLatency),
// Timeout Multiplier
LowerBits(kTimeoutMult),
UpperBits(kTimeoutMult));
auto param_update_rsp = StaticByteBuffer(
LowerBits(
static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)),
UpperBits(
static_cast<uint16_t>(ConnectionParameterUpdateResult::kRejected)));
LowEnergyCommandHandler::ConnectionParameterUpdateRequestCallback cb =
[&](uint16_t interval_min,
uint16_t interval_max,
uint16_t peripheral_latency,
uint16_t timeout_multiplier,
LowEnergyCommandHandler::ConnectionParameterUpdateResponder*
responder) {
EXPECT_EQ(kIntervalMin, interval_min);
EXPECT_EQ(kIntervalMax, interval_max);
EXPECT_EQ(kPeripheralLatency, peripheral_latency);
EXPECT_EQ(kTimeoutMult, timeout_multiplier);
responder->Send(ConnectionParameterUpdateResult::kRejected);
};
cmd_handler()->ServeConnectionParameterUpdateRequest(std::move(cb));
RETURN_IF_FATAL(fake_sig()->ReceiveExpect(
kConnectionParameterUpdateRequest, param_update_req, param_update_rsp));
}
TEST_F(LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqNotEnoughBytes) {
constexpr uint16_t kIntervalMin = 0;
// Request is missing interval max, peripheral latency, and timeout multiplier
// fields.
auto param_update_req = StaticByteBuffer(
// Interval Min
LowerBits(kIntervalMin),
UpperBits(kIntervalMin));
bool cb_called = false;
auto cb = [&](uint16_t interval_min,
uint16_t interval_max,
uint16_t peripheral_latency,
uint16_t timeout_multiplier,
auto responder) { cb_called = true; };
cmd_handler()->ServeConnectionParameterUpdateRequest(std::move(cb));
RETURN_IF_FATAL(fake_sig()->ReceiveExpectRejectNotUnderstood(
kConnectionParameterUpdateRequest, param_update_req));
EXPECT_FALSE(cb_called);
}
} // namespace bt::l2cap::internal