blob: 9c1f15126a49f6f2818a2662f3ddb6c0d062da6f [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/l2cap/low_energy_command_handler.h"
#include "lib/gtest/test_loop_fixture.h"
#include "src/connectivity/bluetooth/core/bt-host/common/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/fake_signaling_channel.h"
namespace bt::l2cap::internal {
using TestBase = ::gtest::TestLoopFixture;
class L2CAP_LowEnergyCommandHandlerTest : public TestBase {
public:
L2CAP_LowEnergyCommandHandlerTest() = default;
~L2CAP_LowEnergyCommandHandlerTest() override = default;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(L2CAP_LowEnergyCommandHandlerTest);
protected:
// TestLoopFixture overrides
void SetUp() override {
TestBase::SetUp();
signaling_channel_ = std::make_unique<testing::FakeSignalingChannel>(dispatcher());
command_handler_ = std::make_unique<LowEnergyCommandHandler>(
fake_sig(), fit::bind_member(this, &L2CAP_LowEnergyCommandHandlerTest::OnRequestFail));
request_fail_callback_ = nullptr;
failed_requests_ = 0;
}
void TearDown() override {
request_fail_callback_ = nullptr;
signaling_channel_ = nullptr;
command_handler_ = nullptr;
TestBase::TearDown();
}
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) {
ZX_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(L2CAP_LowEnergyCommandHandlerTest, OutboundConnParamUpdateReqRspOk) {
constexpr uint16_t kIntervalMin = 0;
constexpr uint16_t kIntervalMax = 1;
constexpr uint16_t kSlaveLatency = 2;
constexpr uint16_t kTimeoutMult = 3;
auto param_update_req = StaticByteBuffer(
// Interval Min
LowerBits(kIntervalMin), UpperBits(kIntervalMin),
// Interval Max
LowerBits(kIntervalMax), UpperBits(kIntervalMax),
// Slave Latency
LowerBits(kSlaveLatency), UpperBits(kSlaveLatency),
// 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)));
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, kSlaveLatency, kTimeoutMult, std::move(rsp_cb)));
RunLoopUntilIdle();
EXPECT_TRUE(cb_called);
}
TEST_F(L2CAP_LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqRspOk) {
constexpr uint16_t kIntervalMin = 0;
constexpr uint16_t kIntervalMax = 1;
constexpr uint16_t kSlaveLatency = 2;
constexpr uint16_t kTimeoutMult = 3;
auto param_update_req = StaticByteBuffer(
// Interval Min
LowerBits(kIntervalMin), UpperBits(kIntervalMin),
// Interval Max
LowerBits(kIntervalMax), UpperBits(kIntervalMax),
// Slave Latency
LowerBits(kSlaveLatency), UpperBits(kSlaveLatency),
// 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 slave_latency,
uint16_t timeout_multiplier,
LowEnergyCommandHandler::ConnectionParameterUpdateResponder* responder) {
EXPECT_EQ(kIntervalMin, interval_min);
EXPECT_EQ(kIntervalMax, interval_max);
EXPECT_EQ(kSlaveLatency, slave_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(L2CAP_LowEnergyCommandHandlerTest, InboundConnParamsUpdateReqNotEnoughBytes) {
constexpr uint16_t kIntervalMin = 0;
// Request is missing interval max, slave 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 slave_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