You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2315 lines
88 KiB
2315 lines
88 KiB
/*
|
|
* Copyright 2020 HIMSA II K/S - www.himsa.com.
|
|
* Represented by EHIMA - www.ehima.com
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "btm_iso_api.h"
|
|
#include "device/include/controller.h"
|
|
#include "main/shim/shim.h"
|
|
#include "mock_controller.h"
|
|
#include "mock_hcic_layer.h"
|
|
|
|
using bluetooth::hci::IsoManager;
|
|
using testing::_;
|
|
using testing::AnyNumber;
|
|
using testing::AtLeast;
|
|
using testing::Eq;
|
|
using testing::Matcher;
|
|
using testing::Return;
|
|
using testing::SaveArg;
|
|
using testing::StrictMock;
|
|
using testing::Test;
|
|
|
|
// Iso Manager currently works on top of the legacy HCI layer
|
|
bool bluetooth::shim::is_gd_shim_enabled() { return false; }
|
|
|
|
namespace bte {
|
|
class BteInterface {
|
|
public:
|
|
virtual void HciSend(BT_HDR* p_msg, uint16_t event) = 0;
|
|
virtual ~BteInterface() = default;
|
|
};
|
|
|
|
class MockBteInterface : public BteInterface {
|
|
public:
|
|
MOCK_METHOD((void), HciSend, (BT_HDR * p_msg, uint16_t event), (override));
|
|
};
|
|
|
|
static MockBteInterface* bte_interface = nullptr;
|
|
static void SetMockBteInterface(MockBteInterface* interface) {
|
|
bte_interface = interface;
|
|
}
|
|
} // namespace bte
|
|
|
|
void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) {
|
|
bte::bte_interface->HciSend(p_msg, event);
|
|
osi_free(p_msg);
|
|
}
|
|
|
|
namespace {
|
|
class MockCigCallbacks : public bluetooth::hci::iso_manager::CigCallbacks {
|
|
public:
|
|
MockCigCallbacks() = default;
|
|
~MockCigCallbacks() override = default;
|
|
|
|
MOCK_METHOD((void), OnSetupIsoDataPath,
|
|
(uint8_t status, uint16_t conn_handle, uint8_t cig_id),
|
|
(override));
|
|
MOCK_METHOD((void), OnRemoveIsoDataPath,
|
|
(uint8_t status, uint16_t conn_handle, uint8_t cig_id),
|
|
(override));
|
|
MOCK_METHOD((void), OnIsoLinkQualityRead,
|
|
(uint8_t conn_handle, uint8_t cig_id, uint32_t txUnackedPackets,
|
|
uint32_t txFlushedPackets, uint32_t txLastSubeventPackets,
|
|
uint32_t retransmittedPackets, uint32_t crcErrorPackets,
|
|
uint32_t rxUnreceivedPackets, uint32_t duplicatePackets),
|
|
(override));
|
|
|
|
MOCK_METHOD((void), OnCisEvent, (uint8_t event, void* data), (override));
|
|
MOCK_METHOD((void), OnCigEvent, (uint8_t event, void* data), (override));
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(MockCigCallbacks);
|
|
};
|
|
|
|
class MockBigCallbacks : public bluetooth::hci::iso_manager::BigCallbacks {
|
|
public:
|
|
MockBigCallbacks() = default;
|
|
~MockBigCallbacks() override = default;
|
|
|
|
MOCK_METHOD((void), OnSetupIsoDataPath,
|
|
(uint8_t status, uint16_t conn_handle, uint8_t big_id),
|
|
(override));
|
|
MOCK_METHOD((void), OnRemoveIsoDataPath,
|
|
(uint8_t status, uint16_t conn_handle, uint8_t big_id),
|
|
(override));
|
|
|
|
MOCK_METHOD((void), OnBigEvent, (uint8_t event, void* data), (override));
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(MockBigCallbacks);
|
|
};
|
|
} // namespace
|
|
|
|
class IsoManagerTest : public Test {
|
|
protected:
|
|
void SetUp() override {
|
|
bte::SetMockBteInterface(&bte_interface_);
|
|
hcic::SetMockHcicInterface(&hcic_interface_);
|
|
controller::SetMockControllerInterface(&controller_interface_);
|
|
|
|
big_callbacks_.reset(new MockBigCallbacks());
|
|
cig_callbacks_.reset(new MockCigCallbacks());
|
|
|
|
EXPECT_CALL(controller_interface_, GetIsoBufferCount())
|
|
.Times(AtLeast(1))
|
|
.WillRepeatedly(Return(6));
|
|
EXPECT_CALL(controller_interface_, GetIsoDataSize())
|
|
.Times(AtLeast(1))
|
|
.WillRepeatedly(Return(1024));
|
|
|
|
InitIsoManager();
|
|
}
|
|
|
|
void TearDown() override {
|
|
CleanupIsoManager();
|
|
|
|
big_callbacks_.reset();
|
|
cig_callbacks_.reset();
|
|
|
|
bte::SetMockBteInterface(nullptr);
|
|
hcic::SetMockHcicInterface(nullptr);
|
|
controller::SetMockControllerInterface(nullptr);
|
|
}
|
|
|
|
virtual void InitIsoManager() {
|
|
manager_instance_ = IsoManager::GetInstance();
|
|
manager_instance_->Start();
|
|
manager_instance_->RegisterCigCallbacks(cig_callbacks_.get());
|
|
manager_instance_->RegisterBigCallbacks(big_callbacks_.get());
|
|
|
|
// Default mock SetCigParams action
|
|
volatile_test_cig_create_cmpl_evt_ = kDefaultCigParamsEvt;
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault([this](auto cig_id, auto,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
uint8_t hci_mock_rsp_buffer
|
|
[3 + sizeof(uint16_t) * this->volatile_test_cig_create_cmpl_evt_
|
|
.conn_handles.size()];
|
|
uint8_t* p = hci_mock_rsp_buffer;
|
|
|
|
UINT8_TO_STREAM(p, this->volatile_test_cig_create_cmpl_evt_.status);
|
|
UINT8_TO_STREAM(p, cig_id);
|
|
UINT8_TO_STREAM(
|
|
p, this->volatile_test_cig_create_cmpl_evt_.conn_handles.size());
|
|
for (auto handle :
|
|
this->volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
UINT16_TO_STREAM(p, handle);
|
|
}
|
|
|
|
std::move(cb).Run(
|
|
hci_mock_rsp_buffer,
|
|
3 + sizeof(uint16_t) * this->volatile_test_cig_create_cmpl_evt_
|
|
.conn_handles.size());
|
|
return 0;
|
|
});
|
|
|
|
// Default mock CreateCis action
|
|
ON_CALL(hcic_interface_, CreateCis)
|
|
.WillByDefault([](uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
for (const EXT_CIS_CREATE_CFG* cis = cis_cfg; num_cis != 0;
|
|
num_cis--, cis++) {
|
|
std::vector<uint8_t> buf(28);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT16_TO_STREAM(p, cis->cis_conn_handle);
|
|
UINT24_TO_STREAM(p, 0xEA); // CIG sync delay
|
|
UINT24_TO_STREAM(p, 0xEB); // CIS sync delay
|
|
UINT24_TO_STREAM(p, 0xEC); // transport latency mtos
|
|
UINT24_TO_STREAM(p, 0xED); // transport latency stom
|
|
UINT8_TO_STREAM(p, 0x01); // phy mtos
|
|
UINT8_TO_STREAM(p, 0x02); // phy stom
|
|
UINT8_TO_STREAM(p, 0x01); // nse
|
|
UINT8_TO_STREAM(p, 0x02); // bn mtos
|
|
UINT8_TO_STREAM(p, 0x03); // bn stom
|
|
UINT8_TO_STREAM(p, 0x04); // ft mtos
|
|
UINT8_TO_STREAM(p, 0x05); // ft stom
|
|
UINT16_TO_STREAM(p, 0x00FA); // Max PDU mtos
|
|
UINT16_TO_STREAM(p, 0x00FB); // Max PDU stom
|
|
UINT16_TO_STREAM(p, 0x0C60); // ISO interval
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT,
|
|
buf.data(), buf.size());
|
|
}
|
|
});
|
|
|
|
// Default mock disconnect action
|
|
ON_CALL(hcic_interface_, Disconnect)
|
|
.WillByDefault([](uint16_t handle, uint8_t reason) {
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, reason);
|
|
});
|
|
|
|
// Default mock CreateBig HCI action
|
|
volatile_test_big_params_evt_ = kDefaultBigParamsEvt;
|
|
ON_CALL(hcic_interface_, CreateBig)
|
|
.WillByDefault(
|
|
[this](auto big_handle,
|
|
bluetooth::hci::iso_manager::big_create_params big_params) {
|
|
std::vector<uint8_t> buf(big_params.num_bis * sizeof(uint16_t) +
|
|
18);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT8_TO_STREAM(p, big_handle);
|
|
|
|
ASSERT_TRUE(big_params.num_bis <=
|
|
volatile_test_big_params_evt_.conn_handles.size());
|
|
|
|
UINT24_TO_STREAM(p, volatile_test_big_params_evt_.big_sync_delay);
|
|
UINT24_TO_STREAM(
|
|
p, volatile_test_big_params_evt_.transport_latency_big);
|
|
UINT8_TO_STREAM(p, big_params.phy);
|
|
UINT8_TO_STREAM(p, volatile_test_big_params_evt_.nse);
|
|
UINT8_TO_STREAM(p, volatile_test_big_params_evt_.bn);
|
|
UINT8_TO_STREAM(p, volatile_test_big_params_evt_.pto);
|
|
UINT8_TO_STREAM(p, volatile_test_big_params_evt_.irc);
|
|
UINT16_TO_STREAM(p, volatile_test_big_params_evt_.max_pdu);
|
|
UINT16_TO_STREAM(p, volatile_test_big_params_evt_.iso_interval);
|
|
|
|
UINT8_TO_STREAM(p, big_params.num_bis);
|
|
for (auto i = 0; i < big_params.num_bis; ++i) {
|
|
UINT16_TO_STREAM(p,
|
|
volatile_test_big_params_evt_.conn_handles[i]);
|
|
}
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(
|
|
HCI_BLE_CREATE_BIG_CPL_EVT, buf.data(), buf.size());
|
|
});
|
|
|
|
// Default mock TerminateBig HCI action
|
|
ON_CALL(hcic_interface_, TerminateBig)
|
|
.WillByDefault([](auto big_handle, uint8_t reason) {
|
|
std::vector<uint8_t> buf(2);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, big_handle);
|
|
UINT8_TO_STREAM(p, reason);
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT,
|
|
buf.data(), buf.size());
|
|
});
|
|
|
|
// Default mock SetupIsoDataPath HCI action
|
|
ON_CALL(hcic_interface_, SetupIsoDataPath)
|
|
.WillByDefault(
|
|
[](uint16_t iso_handle, uint8_t /* data_path_dir */,
|
|
uint8_t /* data_path_id */, uint8_t /* codec_id_format */,
|
|
uint16_t /* codec_id_company */, uint16_t /* codec_id_vendor */,
|
|
uint32_t /* controller_delay */,
|
|
std::vector<uint8_t> /* codec_conf */,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::vector<uint8_t> buf(3);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT16_TO_STREAM(p, iso_handle);
|
|
|
|
std::move(cb).Run(buf.data(), buf.size());
|
|
});
|
|
|
|
// Default mock RemoveIsoDataPath HCI action
|
|
ON_CALL(hcic_interface_, RemoveIsoDataPath)
|
|
.WillByDefault([](uint16_t iso_handle, uint8_t data_path_dir,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::vector<uint8_t> buf(3);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT16_TO_STREAM(p, iso_handle);
|
|
|
|
std::move(cb).Run(buf.data(), buf.size());
|
|
});
|
|
}
|
|
|
|
virtual void CleanupIsoManager() {
|
|
manager_instance_->Stop();
|
|
manager_instance_ = nullptr;
|
|
}
|
|
|
|
static const bluetooth::hci::iso_manager::big_create_params kDefaultBigParams;
|
|
static const bluetooth::hci::iso_manager::cig_create_params kDefaultCigParams;
|
|
static const bluetooth::hci::iso_manager::cig_create_params
|
|
kDefaultCigParams2;
|
|
static const bluetooth::hci::iso_manager::cig_create_cmpl_evt
|
|
kDefaultCigParamsEvt;
|
|
static const bluetooth::hci::iso_manager::big_create_cmpl_evt
|
|
kDefaultBigParamsEvt;
|
|
static const bluetooth::hci::iso_manager::iso_data_path_params
|
|
kDefaultIsoDataPathParams;
|
|
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt
|
|
volatile_test_cig_create_cmpl_evt_;
|
|
bluetooth::hci::iso_manager::big_create_cmpl_evt
|
|
volatile_test_big_params_evt_;
|
|
|
|
IsoManager* manager_instance_;
|
|
bte::MockBteInterface bte_interface_;
|
|
hcic::MockHcicInterface hcic_interface_;
|
|
controller::MockControllerInterface controller_interface_;
|
|
|
|
std::unique_ptr<MockBigCallbacks> big_callbacks_;
|
|
std::unique_ptr<MockCigCallbacks> cig_callbacks_;
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::cig_create_cmpl_evt
|
|
IsoManagerTest::kDefaultCigParamsEvt = {
|
|
.cig_id = 128,
|
|
.status = 0x00,
|
|
.conn_handles = std::vector<uint16_t>({0x0EFF, 0x00FF}),
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::big_create_cmpl_evt
|
|
IsoManagerTest::kDefaultBigParamsEvt = {
|
|
.status = 0x00,
|
|
.big_id = 0,
|
|
.big_sync_delay = 0x0080de,
|
|
.transport_latency_big = 0x00cefe,
|
|
.phy = 0x02,
|
|
.nse = 4,
|
|
.bn = 1,
|
|
.pto = 0,
|
|
.irc = 4,
|
|
.max_pdu = 108,
|
|
.iso_interval = 6,
|
|
.conn_handles = std::vector<uint16_t>({0x0EFE, 0x0E00}),
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::iso_data_path_params
|
|
IsoManagerTest::kDefaultIsoDataPathParams = {
|
|
.data_path_dir = bluetooth::hci::iso_manager::kIsoDataPathDirectionOut,
|
|
.data_path_id = bluetooth::hci::iso_manager::kIsoDataPathHci,
|
|
.codec_id_format = 0x06,
|
|
.codec_id_company = 0,
|
|
.codec_id_vendor = 0,
|
|
.controller_delay = 0,
|
|
.codec_conf = {0x02, 0x01, 0x02},
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::big_create_params
|
|
IsoManagerTest::kDefaultBigParams = {
|
|
.adv_handle = 0x00,
|
|
.num_bis = 2,
|
|
.sdu_itv = 0x002710,
|
|
.max_sdu_size = 108,
|
|
.max_transport_latency = 0x3c,
|
|
.rtn = 3,
|
|
.phy = 0x02,
|
|
.packing = 0x00,
|
|
.framing = 0x00,
|
|
.enc = 0,
|
|
.enc_code = std::array<uint8_t, 16>({0}),
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::cig_create_params
|
|
IsoManagerTest::kDefaultCigParams = {
|
|
.sdu_itv_mtos = 0x00002710,
|
|
.sdu_itv_stom = 0x00002711,
|
|
.sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm,
|
|
.packing = 0x00,
|
|
.framing = 0x01,
|
|
.max_trans_lat_stom = 0x000A,
|
|
.max_trans_lat_mtos = 0x0009,
|
|
.cis_cfgs =
|
|
{
|
|
// CIS #1
|
|
{
|
|
.cis_id = 1,
|
|
.max_sdu_size_mtos = 0x0028,
|
|
.max_sdu_size_stom = 0x0027,
|
|
.phy_mtos = 0x04,
|
|
.phy_stom = 0x03,
|
|
.rtn_mtos = 0x02,
|
|
.rtn_stom = 0x01,
|
|
},
|
|
// CIS #2
|
|
{
|
|
.cis_id = 2,
|
|
.max_sdu_size_mtos = 0x0029,
|
|
.max_sdu_size_stom = 0x002A,
|
|
.phy_mtos = 0x09,
|
|
.phy_stom = 0x08,
|
|
.rtn_mtos = 0x07,
|
|
.rtn_stom = 0x06,
|
|
},
|
|
},
|
|
};
|
|
|
|
const bluetooth::hci::iso_manager::cig_create_params
|
|
IsoManagerTest::kDefaultCigParams2 = {
|
|
.sdu_itv_mtos = 0x00002709,
|
|
.sdu_itv_stom = 0x00002700,
|
|
.sca = bluetooth::hci::iso_manager::kIsoSca0To20Ppm,
|
|
.packing = 0x01,
|
|
.framing = 0x00,
|
|
.max_trans_lat_stom = 0x000B,
|
|
.max_trans_lat_mtos = 0x0006,
|
|
.cis_cfgs =
|
|
{
|
|
// CIS #1
|
|
{
|
|
.cis_id = 1,
|
|
.max_sdu_size_mtos = 0x0022,
|
|
.max_sdu_size_stom = 0x0022,
|
|
.phy_mtos = 0x01,
|
|
.phy_stom = 0x02,
|
|
.rtn_mtos = 0x02,
|
|
.rtn_stom = 0x01,
|
|
},
|
|
// CIS #2
|
|
{
|
|
.cis_id = 2,
|
|
.max_sdu_size_mtos = 0x002A,
|
|
.max_sdu_size_stom = 0x002B,
|
|
.phy_mtos = 0x06,
|
|
.phy_stom = 0x06,
|
|
.rtn_mtos = 0x07,
|
|
.rtn_stom = 0x07,
|
|
},
|
|
},
|
|
};
|
|
|
|
class IsoManagerDeathTest : public IsoManagerTest {};
|
|
|
|
class IsoManagerDeathTestNoInit : public IsoManagerTest {
|
|
protected:
|
|
void InitIsoManager() override { /* DO NOTHING */
|
|
}
|
|
|
|
void CleanupIsoManager() override { /* DO NOTHING */
|
|
}
|
|
};
|
|
|
|
class IsoManagerDeathTestNoCleanup : public IsoManagerTest {
|
|
protected:
|
|
void CleanupIsoManager() override { /* DO NOTHING */
|
|
}
|
|
};
|
|
|
|
bool operator==(const EXT_CIS_CFG& x, const EXT_CIS_CFG& y) {
|
|
return ((x.cis_id == y.cis_id) &&
|
|
(x.max_sdu_size_mtos == y.max_sdu_size_mtos) &&
|
|
(x.max_sdu_size_stom == y.max_sdu_size_stom) &&
|
|
(x.phy_mtos == y.phy_mtos) && (x.phy_stom == y.phy_stom) &&
|
|
(x.rtn_mtos == y.rtn_mtos) && (x.rtn_stom == y.rtn_stom));
|
|
}
|
|
|
|
bool operator==(
|
|
const struct bluetooth::hci::iso_manager::cig_create_params& x,
|
|
const struct bluetooth::hci::iso_manager::cig_create_params& y) {
|
|
return ((x.sdu_itv_mtos == y.sdu_itv_mtos) &&
|
|
(x.sdu_itv_stom == y.sdu_itv_stom) && (x.sca == y.sca) &&
|
|
(x.packing == y.packing) && (x.framing == y.framing) &&
|
|
(x.max_trans_lat_stom == y.max_trans_lat_stom) &&
|
|
(x.max_trans_lat_mtos == y.max_trans_lat_mtos) &&
|
|
std::is_permutation(x.cis_cfgs.begin(), x.cis_cfgs.end(),
|
|
y.cis_cfgs.begin()));
|
|
}
|
|
|
|
bool operator==(
|
|
const struct bluetooth::hci::iso_manager::big_create_params& x,
|
|
const struct bluetooth::hci::iso_manager::big_create_params& y) {
|
|
return ((x.adv_handle == y.adv_handle) && (x.num_bis == y.num_bis) &&
|
|
(x.sdu_itv == y.sdu_itv) && (x.max_sdu_size == y.max_sdu_size) &&
|
|
(x.max_transport_latency == y.max_transport_latency) &&
|
|
(x.rtn == y.rtn) && (x.phy == y.phy) && (x.packing == y.packing) &&
|
|
(x.framing == y.framing) && (x.enc == y.enc) &&
|
|
(x.enc_code == y.enc_code));
|
|
}
|
|
|
|
namespace iso_matchers {
|
|
MATCHER_P(Eq, value, "") { return (arg == value); }
|
|
MATCHER_P2(EqPointedArray, value, len, "") {
|
|
return (!std::memcmp(arg, value, len));
|
|
}
|
|
} // namespace iso_matchers
|
|
|
|
TEST_F(IsoManagerTest, SingletonAccess) {
|
|
auto* iso_mgr = IsoManager::GetInstance();
|
|
ASSERT_EQ(manager_instance_, iso_mgr);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, RegisterCallbacks) {
|
|
auto* iso_mgr = IsoManager::GetInstance();
|
|
ASSERT_EQ(manager_instance_, iso_mgr);
|
|
|
|
iso_mgr->RegisterBigCallbacks(new MockBigCallbacks());
|
|
iso_mgr->RegisterCigCallbacks(new MockCigCallbacks());
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTestNoInit, RegisterNullBigCallbacks) {
|
|
IsoManager::GetInstance()->Start();
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->RegisterBigCallbacks(nullptr),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid BIG callbacks");
|
|
|
|
// Manual cleanup as IsoManagerDeathTest has no 'generic' cleanup
|
|
IsoManager::GetInstance()->Stop();
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTestNoInit, RegisterNullCigCallbacks) {
|
|
IsoManager::GetInstance()->Start();
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->RegisterCigCallbacks(nullptr),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid CIG callbacks");
|
|
|
|
// Manual cleanup as IsoManagerDeathTest has no 'generic' cleanup
|
|
IsoManager::GetInstance()->Stop();
|
|
}
|
|
|
|
// Verify hci layer being called by the Iso Manager
|
|
TEST_F(IsoManagerTest, CreateCigHciCall) {
|
|
for (uint8_t i = 220; i != 60; ++i) {
|
|
EXPECT_CALL(hcic_interface_,
|
|
SetCigParams(i, iso_matchers::Eq(kDefaultCigParams), _))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->CreateCig(i, kDefaultCigParams);
|
|
}
|
|
}
|
|
|
|
// Check handling create cig request twice with the same CIG id
|
|
TEST_F(IsoManagerDeathTest, CreateSameCigTwice) {
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
|
|
evt.status = 0x01;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
volatile_test_cig_create_cmpl_evt_.cig_id = 127;
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
ASSERT_EQ(evt.status, HCI_SUCCESS);
|
|
|
|
// Second call with the same CIG ID should fail
|
|
ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams),
|
|
::testing::KilledBySignal(SIGABRT), "already exists");
|
|
}
|
|
|
|
// Check for handling invalid length response from the faulty controller
|
|
TEST_F(IsoManagerDeathTest, CreateCigCallbackInvalidRspPacket) {
|
|
uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00};
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(128, kDefaultCigParams),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
// Check for handling invalid length response from the faulty controller
|
|
TEST_F(IsoManagerDeathTest, CreateCigCallbackInvalidRspPacket2) {
|
|
uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00, 0x02, 0x01, 0x00};
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->CreateCig(128, kDefaultCigParams),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid CIS count");
|
|
}
|
|
|
|
// Check if IsoManager properly handles error responses from HCI layer
|
|
TEST_F(IsoManagerTest, CreateCigCallbackInvalidStatus) {
|
|
uint8_t rsp_cig_id = 128;
|
|
uint8_t rsp_status = 0x01;
|
|
uint8_t rsp_cis_cnt = 3;
|
|
uint8_t hci_mock_rsp_buffer[] = {rsp_status, rsp_cig_id, rsp_cis_cnt};
|
|
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateCig(rsp_cig_id, kDefaultCigParams);
|
|
ASSERT_EQ(evt.cig_id, rsp_cig_id);
|
|
ASSERT_EQ(evt.status, rsp_status);
|
|
ASSERT_TRUE(evt.conn_handles.empty());
|
|
}
|
|
|
|
// Check valid callback response
|
|
TEST_F(IsoManagerTest, CreateCigCallbackValid) {
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.status, volatile_test_cig_create_cmpl_evt_.status);
|
|
ASSERT_EQ(evt.conn_handles.size(), 2u);
|
|
ASSERT_TRUE(
|
|
std::is_permutation(evt.conn_handles.begin(), evt.conn_handles.end(),
|
|
std::vector<uint16_t>({0x0EFF, 0x00FF}).begin()));
|
|
}
|
|
|
|
// Check if CIG reconfigure triggers HCI layer call
|
|
TEST_F(IsoManagerTest, ReconfigureCigHciCall) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
EXPECT_CALL(hcic_interface_,
|
|
SetCigParams(volatile_test_cig_create_cmpl_evt_.cig_id,
|
|
iso_matchers::Eq(kDefaultCigParams), _))
|
|
.Times(1);
|
|
IsoManager::GetInstance()->ReconfigureCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
}
|
|
|
|
// Verify handlidng invalid call - reconfiguring invalid CIG
|
|
TEST_F(IsoManagerDeathTest, ReconfigureCigWithNoSuchCig) {
|
|
ASSERT_EXIT(IsoManager::GetInstance()->ReconfigureCig(128, kDefaultCigParams),
|
|
::testing::KilledBySignal(SIGABRT), "No such cig");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, ReconfigureCigInvalidRspPacket) {
|
|
uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00};
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
ASSERT_EXIT(IsoManager::GetInstance()->ReconfigureCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, ReconfigureCigInvalidRspPacket2) {
|
|
uint8_t hci_mock_rsp_buffer[] = {0x00, 0x00, 0x02, 0x01, 0x00};
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->ReconfigureCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams2),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid CIS count");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, ReconfigureCigInvalidStatus) {
|
|
uint8_t rsp_cig_id = 128;
|
|
uint8_t rsp_status = 0x01;
|
|
uint8_t rsp_cis_cnt = 3;
|
|
uint8_t hci_mock_rsp_buffer[] = {rsp_status, rsp_cig_id, rsp_cis_cnt};
|
|
|
|
IsoManager::GetInstance()->CreateCig(rsp_cig_id, kDefaultCigParams);
|
|
|
|
// Set-up the invalid response
|
|
ON_CALL(hcic_interface_, SetCigParams)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnReconfigureCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
IsoManager::GetInstance()->ReconfigureCig(rsp_cig_id, kDefaultCigParams2);
|
|
|
|
ASSERT_EQ(evt.cig_id, rsp_cig_id);
|
|
ASSERT_EQ(evt.status, rsp_status);
|
|
ASSERT_TRUE(evt.conn_handles.empty());
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, ReconfigureCigValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cig_create_cmpl_evt evt;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnReconfigureCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
// Verify valid reconfiguration request
|
|
IsoManager::GetInstance()->ReconfigureCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams2);
|
|
ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.status, volatile_test_cig_create_cmpl_evt_.status);
|
|
ASSERT_TRUE(std::is_permutation(
|
|
evt.conn_handles.begin(), evt.conn_handles.end(),
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.begin()));
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, RemoveCigHciCall) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
EXPECT_CALL(hcic_interface_,
|
|
RemoveCig(volatile_test_cig_create_cmpl_evt_.cig_id, _))
|
|
.Times(1);
|
|
IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, RemoveCigWithNoSuchCig) {
|
|
ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id),
|
|
::testing::KilledBySignal(SIGABRT), "No such cig");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, RemoveSameCigTwice) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, RemoveCig)
|
|
.WillByDefault(
|
|
[this](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
uint8_t hci_mock_rsp_buffer[2];
|
|
uint8_t* p = hci_mock_rsp_buffer;
|
|
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT8_TO_STREAM(p, this->volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id),
|
|
::testing::KilledBySignal(SIGABRT), "No such cig");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, RemoveCigInvalidRspPacket) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, RemoveCig)
|
|
.WillByDefault([](auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
uint8_t hci_mock_rsp_buffer[] = {0x00}; // status byte only
|
|
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
ASSERT_EXIT(IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, RemoveCigInvalidStatus) {
|
|
uint8_t rsp_status = 0x02;
|
|
uint8_t hci_mock_rsp_buffer[] = {rsp_status,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id};
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, RemoveCig)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
bluetooth::hci::iso_manager::cig_remove_cmpl_evt evt;
|
|
ON_CALL(*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnRemoveCmpl, _))
|
|
.WillByDefault([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_remove_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.status, rsp_status);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, RemoveCigValid) {
|
|
uint8_t hci_mock_rsp_buffer[] = {HCI_SUCCESS,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id};
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, RemoveCig)
|
|
.WillByDefault(
|
|
[&hci_mock_rsp_buffer](
|
|
auto, base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run(hci_mock_rsp_buffer, sizeof(hci_mock_rsp_buffer));
|
|
return 0;
|
|
});
|
|
|
|
bluetooth::hci::iso_manager::cig_remove_cmpl_evt evt;
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCigEvent(bluetooth::hci::iso_manager::kIsoEventCigOnRemoveCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::cig_remove_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->RemoveCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(evt.status, HCI_SUCCESS);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, EstablishCisHciCall) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
|
|
EXPECT_CALL(hcic_interface_,
|
|
CreateCis(2,
|
|
iso_matchers::EqPointedArray(
|
|
params.conn_pairs.data(),
|
|
params.conn_pairs.size() *
|
|
sizeof(params.conn_pairs.data()[0])),
|
|
_))
|
|
.Times(1);
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, EstablishCisWithNoSuchCis) {
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(
|
|
params),
|
|
::testing::KilledBySignal(SIGABRT), "No such cis");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, ConnectSameCisTwice) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(
|
|
params),
|
|
::testing::KilledBySignal(SIGABRT), "Already connected");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, EstablishCisInvalidResponsePacket) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
ON_CALL(hcic_interface_, CreateCis)
|
|
.WillByDefault([this](uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
std::vector<uint8_t> buf(27);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, HCI_SUCCESS);
|
|
UINT16_TO_STREAM(p, handle);
|
|
UINT24_TO_STREAM(p, 0xEA); // CIG sync delay
|
|
UINT24_TO_STREAM(p, 0xEB); // CIS sync delay
|
|
UINT24_TO_STREAM(p, 0xEC); // transport latency mtos
|
|
UINT24_TO_STREAM(p, 0xED); // transport latency stom
|
|
UINT8_TO_STREAM(p, 0x01); // phy mtos
|
|
UINT8_TO_STREAM(p, 0x02); // phy stom
|
|
UINT8_TO_STREAM(p, 0x01); // nse
|
|
UINT8_TO_STREAM(p, 0x02); // bn mtos
|
|
UINT8_TO_STREAM(p, 0x03); // bn stom
|
|
UINT8_TO_STREAM(p, 0x04); // ft mtos
|
|
UINT8_TO_STREAM(p, 0x05); // ft stom
|
|
UINT16_TO_STREAM(p, 0x00FA); // Max PDU mtos
|
|
UINT16_TO_STREAM(p, 0x00FB); // Max PDU stom
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT,
|
|
buf.data(), buf.size());
|
|
}
|
|
});
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->EstablishCis(
|
|
params),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, EstablishCisInvalidCommandStatus) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
uint16_t invalid_status = 0x0001;
|
|
|
|
ON_CALL(hcic_interface_, CreateCis)
|
|
.WillByDefault([invalid_status](
|
|
uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::move(cb).Run((uint8_t*)&invalid_status, sizeof(invalid_status));
|
|
return 0;
|
|
});
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
|
|
.Times(kDefaultCigParams.cis_cfgs.size())
|
|
.WillRepeatedly([this, invalid_status](uint8_t type, void* data) {
|
|
bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
|
|
static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(
|
|
data);
|
|
|
|
ASSERT_EQ(evt->status, invalid_status);
|
|
ASSERT_TRUE(
|
|
std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
|
|
evt->cis_conn_hdl) !=
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end());
|
|
});
|
|
|
|
// Establish all CISes
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, EstablishCisInvalidStatus) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
uint8_t invalid_status = 0x01;
|
|
|
|
ON_CALL(hcic_interface_, CreateCis)
|
|
.WillByDefault([this, invalid_status](
|
|
uint8_t num_cis, const EXT_CIS_CREATE_CFG* cis_cfg,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
std::vector<uint8_t> buf(28);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, invalid_status);
|
|
UINT16_TO_STREAM(p, handle);
|
|
UINT24_TO_STREAM(p, 0xEA); // CIG sync delay
|
|
UINT24_TO_STREAM(p, 0xEB); // CIS sync delay
|
|
UINT24_TO_STREAM(p, 0xEC); // transport latency mtos
|
|
UINT24_TO_STREAM(p, 0xED); // transport latency stom
|
|
UINT8_TO_STREAM(p, 0x01); // phy mtos
|
|
UINT8_TO_STREAM(p, 0x02); // phy stom
|
|
UINT8_TO_STREAM(p, 0x01); // nse
|
|
UINT8_TO_STREAM(p, 0x02); // bn mtos
|
|
UINT8_TO_STREAM(p, 0x03); // bn stom
|
|
UINT8_TO_STREAM(p, 0x04); // ft mtos
|
|
UINT8_TO_STREAM(p, 0x05); // ft stom
|
|
UINT16_TO_STREAM(p, 0x00FA); // Max PDU mtos
|
|
UINT16_TO_STREAM(p, 0x00FB); // Max PDU stom
|
|
UINT16_TO_STREAM(p, 0x0C60); // ISO interval
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_CIS_EST_EVT,
|
|
buf.data(), buf.size());
|
|
}
|
|
});
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
|
|
.Times(kDefaultCigParams.cis_cfgs.size())
|
|
.WillRepeatedly([this, invalid_status](uint8_t type, void* data) {
|
|
bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
|
|
static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(
|
|
data);
|
|
|
|
ASSERT_EQ(evt->status, invalid_status);
|
|
ASSERT_TRUE(
|
|
std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
|
|
evt->cis_conn_hdl) !=
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end());
|
|
});
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, EstablishCisValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
|
|
.Times(kDefaultCigParams.cis_cfgs.size())
|
|
.WillRepeatedly([this](uint8_t type, void* data) {
|
|
bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
|
|
static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(
|
|
data);
|
|
|
|
ASSERT_EQ(evt->status, HCI_SUCCESS);
|
|
ASSERT_TRUE(
|
|
std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
|
|
evt->cis_conn_hdl) !=
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end());
|
|
});
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, ReconnectCisValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
// trigger HCI disconnection event
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 0x16);
|
|
}
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisEstablishCmpl, _))
|
|
.Times(kDefaultCigParams.cis_cfgs.size())
|
|
.WillRepeatedly([this](uint8_t type, void* data) {
|
|
bluetooth::hci::iso_manager::cis_establish_cmpl_evt* evt =
|
|
static_cast<bluetooth::hci::iso_manager::cis_establish_cmpl_evt*>(
|
|
data);
|
|
|
|
ASSERT_EQ(evt->status, HCI_SUCCESS);
|
|
ASSERT_TRUE(
|
|
std::find(volatile_test_cig_create_cmpl_evt_.conn_handles.begin(),
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end(),
|
|
evt->cis_conn_hdl) !=
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles.end());
|
|
});
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, DisconnectCisHciCall) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
EXPECT_CALL(hcic_interface_, Disconnect(handle, 0x16))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle,
|
|
0x16);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, DisconnectCisWithNoSuchCis) {
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(
|
|
handle, 0x16),
|
|
::testing::KilledBySignal(SIGABRT), "No such cis");
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, DisconnectSameCisTwice) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle,
|
|
0x16);
|
|
}
|
|
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(
|
|
handle, 0x16),
|
|
::testing::KilledBySignal(SIGABRT), "Not connected");
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, DisconnectCisValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
uint8_t disconnect_reason = 0x16;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent)
|
|
.WillOnce([this, handle, disconnect_reason](uint8_t event_code,
|
|
void* data) {
|
|
ASSERT_EQ(event_code,
|
|
bluetooth::hci::iso_manager::kIsoEventCisDisconnected);
|
|
auto* event =
|
|
static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(
|
|
data);
|
|
ASSERT_EQ(event->reason, disconnect_reason);
|
|
ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(event->cis_conn_hdl, handle);
|
|
})
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(
|
|
handle, disconnect_reason);
|
|
}
|
|
}
|
|
|
|
// Check if we properly ignore not ISO related disconnect events
|
|
TEST_F(IsoManagerDeathTest, DisconnectCisInvalidResponse) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
// Make the HCI layer send invalid handles in disconnect event
|
|
ON_CALL(hcic_interface_, Disconnect)
|
|
.WillByDefault([](uint16_t handle, uint8_t reason) {
|
|
IsoManager::GetInstance()->HandleDisconnect(handle + 1, reason);
|
|
});
|
|
|
|
// We don't expect any calls as these are not ISO handles
|
|
ON_CALL(*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
|
|
.WillByDefault([](uint8_t event_code, void* data) { FAIL(); });
|
|
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->IsoManager::GetInstance()->DisconnectCis(handle,
|
|
0x16);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, CreateBigHciCall) {
|
|
for (uint8_t i = 220; i != 60; ++i) {
|
|
EXPECT_CALL(hcic_interface_,
|
|
CreateBig(i, iso_matchers::Eq(kDefaultBigParams)))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->CreateBig(i, kDefaultBigParams);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, CreateBigValid) {
|
|
bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
|
|
evt.status = 0x01;
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
|
|
ASSERT_EQ(evt.status, HCI_SUCCESS);
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, CreateBigInvalidResponsePacket) {
|
|
ON_CALL(hcic_interface_, CreateBig)
|
|
.WillByDefault(
|
|
[](auto big_handle,
|
|
bluetooth::hci::iso_manager::big_create_params big_params) {
|
|
std::vector<uint8_t> buf(18);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, 0x00);
|
|
UINT8_TO_STREAM(p, big_handle);
|
|
|
|
UINT24_TO_STREAM(p, 0x0080de); // big_sync_delay
|
|
UINT24_TO_STREAM(p, 0x00cefe); // transport_latency_big
|
|
UINT8_TO_STREAM(p, big_params.phy); // phy
|
|
UINT8_TO_STREAM(p, 4); // nse
|
|
UINT8_TO_STREAM(p, 1); // bn
|
|
UINT8_TO_STREAM(p, 0); // pto
|
|
UINT8_TO_STREAM(p, 4); // irc
|
|
UINT16_TO_STREAM(p, 108); // max_pdu
|
|
UINT16_TO_STREAM(p, 6); // iso_interval
|
|
UINT8_TO_STREAM(p, 0); // num BISes
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(
|
|
HCI_BLE_CREATE_BIG_CPL_EVT, buf.data(), buf.size());
|
|
});
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid bis count");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, CreateBigInvalidResponsePacket2) {
|
|
ON_CALL(hcic_interface_, CreateBig)
|
|
.WillByDefault(
|
|
[](auto big_handle,
|
|
bluetooth::hci::iso_manager::big_create_params big_params) {
|
|
std::vector<uint8_t> buf(18);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, 0x00);
|
|
UINT8_TO_STREAM(p, big_handle);
|
|
|
|
UINT24_TO_STREAM(p, 0x0080de); // big_sync_delay
|
|
UINT24_TO_STREAM(p, 0x00cefe); // transport_latency_big
|
|
UINT8_TO_STREAM(p, big_params.phy); // phy
|
|
UINT8_TO_STREAM(p, 4); // nse
|
|
UINT8_TO_STREAM(p, 1); // bn
|
|
UINT8_TO_STREAM(p, 0); // pto
|
|
UINT8_TO_STREAM(p, 4); // irc
|
|
UINT16_TO_STREAM(p, 108); // max_pdu
|
|
UINT16_TO_STREAM(p, 6); // iso_interval
|
|
UINT8_TO_STREAM(p, big_params.num_bis);
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(
|
|
HCI_BLE_CREATE_BIG_CPL_EVT, buf.data(), buf.size());
|
|
});
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, CreateBigInvalidStatus) {
|
|
bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
|
|
evt.status = 0x00;
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
ON_CALL(hcic_interface_, CreateBig)
|
|
.WillByDefault(
|
|
[](auto big_handle,
|
|
bluetooth::hci::iso_manager::big_create_params big_params) {
|
|
std::vector<uint8_t> buf(big_params.num_bis * sizeof(uint16_t) +
|
|
18);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, 0x01);
|
|
UINT8_TO_STREAM(p, big_handle);
|
|
|
|
UINT24_TO_STREAM(p, 0x0080de); // big_sync_delay
|
|
UINT24_TO_STREAM(p, 0x00cefe); // transport_latency_big
|
|
UINT8_TO_STREAM(p, big_params.phy); // phy
|
|
UINT8_TO_STREAM(p, 4); // nse
|
|
UINT8_TO_STREAM(p, 1); // bn
|
|
UINT8_TO_STREAM(p, 0); // pto
|
|
UINT8_TO_STREAM(p, 4); // irc
|
|
UINT16_TO_STREAM(p, 108); // max_pdu
|
|
UINT16_TO_STREAM(p, 6); // iso_interval
|
|
|
|
UINT8_TO_STREAM(p, big_params.num_bis);
|
|
static uint8_t conn_hdl = 0x01;
|
|
for (auto i = 0; i < big_params.num_bis; ++i) {
|
|
UINT16_TO_STREAM(p, conn_hdl++);
|
|
}
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(
|
|
HCI_BLE_CREATE_BIG_CPL_EVT, buf.data(), buf.size());
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
|
|
ASSERT_EQ(evt.status, 0x01);
|
|
ASSERT_EQ(evt.big_id, 0x01);
|
|
ASSERT_EQ(evt.conn_handles.size(), kDefaultBigParams.num_bis);
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, CreateSameBigTwice) {
|
|
bluetooth::hci::iso_manager::big_create_cmpl_evt evt;
|
|
evt.status = 0x01;
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt = *static_cast<bluetooth::hci::iso_manager::big_create_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateBig(0x01, kDefaultBigParams);
|
|
ASSERT_EQ(evt.status, HCI_SUCCESS);
|
|
ASSERT_EQ(evt.big_id, 0x01);
|
|
ASSERT_EQ(evt.conn_handles.size(), kDefaultBigParams.num_bis);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, TerminateBigHciCall) {
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
EXPECT_CALL(hcic_interface_, TerminateBig(big_id, reason)).Times(1);
|
|
IsoManager::GetInstance()->TerminateBig(big_id, reason);
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, TerminateSameBigTwice) {
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _));
|
|
|
|
IsoManager::GetInstance()->TerminateBig(big_id, reason);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
|
|
::testing::KilledBySignal(SIGABRT), "No such big");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, TerminateBigNoSuchBig) {
|
|
const uint8_t big_id = 0x01;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnCreateCmpl, _));
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
|
|
ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id + 1, reason),
|
|
::testing::KilledBySignal(SIGABRT), "No such big");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, TerminateBigInvalidResponsePacket) {
|
|
ON_CALL(hcic_interface_, TerminateBig)
|
|
.WillByDefault([](auto big_handle, uint8_t reason) {
|
|
std::vector<uint8_t> buf(1);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, reason);
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT,
|
|
buf.data(), buf.size());
|
|
});
|
|
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, TerminateBigInvalidResponsePacket2) {
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
ON_CALL(hcic_interface_, TerminateBig)
|
|
.WillByDefault([](auto big_handle, uint8_t reason) {
|
|
std::vector<uint8_t> buf(3);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, reason);
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT,
|
|
buf.data(), buf.size());
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
|
|
::testing::KilledBySignal(SIGABRT), "Invalid packet length");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, TerminateBigInvalidResponseBigId) {
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
|
|
ON_CALL(hcic_interface_, TerminateBig)
|
|
.WillByDefault([](auto big_handle, uint8_t reason) {
|
|
std::vector<uint8_t> buf(2);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, reason);
|
|
UINT8_TO_STREAM(p, big_handle + 1);
|
|
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT,
|
|
buf.data(), buf.size());
|
|
});
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->TerminateBig(big_id, reason),
|
|
::testing::KilledBySignal(SIGABRT), "No such big");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, TerminateBigValid) {
|
|
const uint8_t big_id = 0x22;
|
|
const uint8_t reason = 0x16; // Terminated by local host
|
|
bluetooth::hci::iso_manager::big_terminate_cmpl_evt evt;
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _))
|
|
.WillOnce([&evt](uint8_t type, void* data) {
|
|
evt =
|
|
*static_cast<bluetooth::hci::iso_manager::big_terminate_cmpl_evt*>(
|
|
data);
|
|
return 0;
|
|
});
|
|
|
|
IsoManager::GetInstance()->TerminateBig(big_id, reason);
|
|
ASSERT_EQ(evt.big_id, big_id);
|
|
ASSERT_EQ(evt.reason, reason);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SetupIsoDataPathValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
bluetooth::hci::iso_manager::iso_data_path_params path_params =
|
|
kDefaultIsoDataPathParams;
|
|
|
|
// Setup data paths for all CISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
EXPECT_CALL(*cig_callbacks_,
|
|
OnSetupIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
|
|
path_params.data_path_dir =
|
|
(bluetooth::hci::iso_manager::kIsoDataPathDirectionIn + handle) % 2;
|
|
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
|
|
// Setup data paths for all BISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
|
|
for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
|
|
std::cerr << "setting up BIS data path on conn_hdl: " << int{handle};
|
|
EXPECT_CALL(*big_callbacks_,
|
|
OnSetupIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_big_params_evt_.big_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SetupIsoDataPathTwice) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
// Establish CISes
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
// Setup data paths for all CISes twice
|
|
bluetooth::hci::iso_manager::iso_data_path_params path_params =
|
|
kDefaultIsoDataPathParams;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
// Should be possible to reconfigure
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
// Setup data paths for all BISes twice
|
|
for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
// Should be possible to reconfigure
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SetupIsoDataPathInvalidStatus) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
bluetooth::hci::iso_manager::iso_data_path_params path_params =
|
|
kDefaultIsoDataPathParams;
|
|
|
|
uint8_t setup_datapath_rsp_status = HCI_SUCCESS;
|
|
ON_CALL(hcic_interface_, SetupIsoDataPath)
|
|
.WillByDefault([&setup_datapath_rsp_status](
|
|
uint16_t iso_handle, uint8_t, uint8_t, uint8_t,
|
|
uint16_t, uint16_t, uint32_t, std::vector<uint8_t>,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::vector<uint8_t> buf(3);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, setup_datapath_rsp_status);
|
|
UINT16_TO_STREAM(p, iso_handle);
|
|
|
|
std::move(cb).Run(buf.data(), buf.size());
|
|
});
|
|
|
|
// Try to setup data paths for all CISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
// Mock the response with status != HCI_SUCCESS
|
|
EXPECT_CALL(*cig_callbacks_,
|
|
OnSetupIsoDataPath(0x11, handle,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
setup_datapath_rsp_status = 0x11;
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
|
|
// It should be possible to retry on the same handle after the first
|
|
// failure
|
|
EXPECT_CALL(*cig_callbacks_,
|
|
OnSetupIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
setup_datapath_rsp_status = HCI_SUCCESS;
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
|
|
// Try to setup data paths for all BISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
|
|
for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnSetupIsoDataPath(0x11, handle, volatile_test_big_params_evt_.big_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
setup_datapath_rsp_status = 0x11;
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
|
|
EXPECT_CALL(*big_callbacks_,
|
|
OnSetupIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_big_params_evt_.big_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
setup_datapath_rsp_status = HCI_SUCCESS;
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, RemoveIsoDataPathValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
|
|
// Establish all CISes before setting up their data paths
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
bluetooth::hci::iso_manager::iso_data_path_params path_params =
|
|
kDefaultIsoDataPathParams;
|
|
|
|
// Setup and remove data paths for all CISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionIn;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
|
|
EXPECT_CALL(*cig_callbacks_,
|
|
OnRemoveIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(handle,
|
|
path_params.data_path_dir);
|
|
}
|
|
|
|
// Setup and remove data paths for all BISes
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
|
|
for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
|
|
std::cerr << "setting up BIS data path on conn_hdl: " << int{handle};
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
|
|
EXPECT_CALL(*big_callbacks_,
|
|
OnRemoveIsoDataPath(HCI_SUCCESS, handle,
|
|
volatile_test_big_params_evt_.big_id))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(handle,
|
|
path_params.data_path_dir);
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, RemoveIsoDataPathNoSuchPath) {
|
|
// Check on CIS
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
|
|
::testing::KilledBySignal(SIGABRT), "path not set");
|
|
|
|
IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
|
|
::testing::KilledBySignal(SIGABRT), "path not set");
|
|
|
|
// Check on BIS
|
|
iso_handle = volatile_test_big_params_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
|
|
::testing::KilledBySignal(SIGABRT), "path not set");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, RemoveIsoDataPathTwice) {
|
|
// Check on CIS
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
|
|
IsoManager::GetInstance()->SetupIsoDataPath(iso_handle,
|
|
kDefaultIsoDataPathParams);
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, kDefaultIsoDataPathParams.data_path_dir);
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
|
|
::testing::KilledBySignal(SIGABRT), "path not set");
|
|
|
|
// Check on BIS
|
|
iso_handle = volatile_test_big_params_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
IsoManager::GetInstance()->SetupIsoDataPath(iso_handle,
|
|
kDefaultIsoDataPathParams);
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, kDefaultIsoDataPathParams.data_path_dir);
|
|
ASSERT_EXIT(
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, bluetooth::hci::iso_manager::kIsoDataPathDirectionOut),
|
|
::testing::KilledBySignal(SIGABRT), "path not set");
|
|
}
|
|
|
|
// Check if HCI status other than HCI_SUCCESS is being propagated to the caller
|
|
TEST_F(IsoManagerTest, RemoveIsoDataPathInvalidStatus) {
|
|
// Mock invalid status response
|
|
uint8_t remove_datapath_rsp_status = 0x12;
|
|
ON_CALL(hcic_interface_, RemoveIsoDataPath)
|
|
.WillByDefault([&remove_datapath_rsp_status](
|
|
uint16_t iso_handle, uint8_t data_path_dir,
|
|
base::OnceCallback<void(uint8_t*, uint16_t)> cb) {
|
|
std::vector<uint8_t> buf(3);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, remove_datapath_rsp_status);
|
|
UINT16_TO_STREAM(p, iso_handle);
|
|
|
|
std::move(cb).Run(buf.data(), buf.size());
|
|
});
|
|
|
|
// Check on CIS
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
uint16_t iso_handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({.conn_pairs = {{iso_handle, 1}}});
|
|
IsoManager::GetInstance()->SetupIsoDataPath(iso_handle,
|
|
kDefaultIsoDataPathParams);
|
|
|
|
EXPECT_CALL(*cig_callbacks_,
|
|
OnRemoveIsoDataPath(remove_datapath_rsp_status, iso_handle,
|
|
volatile_test_cig_create_cmpl_evt_.cig_id))
|
|
.Times(1);
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, kDefaultIsoDataPathParams.data_path_dir);
|
|
|
|
// Check on BIS
|
|
iso_handle = volatile_test_big_params_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
IsoManager::GetInstance()->SetupIsoDataPath(iso_handle,
|
|
kDefaultIsoDataPathParams);
|
|
|
|
EXPECT_CALL(*big_callbacks_,
|
|
OnRemoveIsoDataPath(remove_datapath_rsp_status, iso_handle,
|
|
volatile_test_big_params_evt_.big_id))
|
|
.Times(1);
|
|
IsoManager::GetInstance()->RemoveIsoDataPath(
|
|
iso_handle, kDefaultIsoDataPathParams.data_path_dir);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SendIsoDataCigValid) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
bluetooth::hci::iso_manager::iso_data_path_params path_params =
|
|
kDefaultIsoDataPathParams;
|
|
path_params.data_path_dir =
|
|
bluetooth::hci::iso_manager::kIsoDataPathDirectionOut;
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle, path_params);
|
|
|
|
for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) {
|
|
constexpr uint8_t data_len = 108;
|
|
|
|
EXPECT_CALL(bte_interface_, HciSend)
|
|
.WillOnce([handle, data_len](BT_HDR* p_msg, uint16_t event) {
|
|
uint8_t* p = p_msg->data;
|
|
uint16_t msg_handle;
|
|
uint16_t iso_load_len;
|
|
|
|
ASSERT_TRUE((event & MSG_STACK_TO_HC_HCI_ISO) != 0);
|
|
ASSERT_NE(p_msg, nullptr);
|
|
ASSERT_EQ(p_msg->len, data_len + ((p_msg->layer_specific &
|
|
BT_ISO_HDR_CONTAINS_TS)
|
|
? 12
|
|
: 8));
|
|
|
|
// Verify packet internals
|
|
STREAM_TO_UINT16(msg_handle, p);
|
|
ASSERT_EQ(msg_handle, handle);
|
|
|
|
STREAM_TO_UINT16(iso_load_len, p);
|
|
ASSERT_EQ(
|
|
iso_load_len,
|
|
data_len +
|
|
((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4));
|
|
|
|
if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) {
|
|
STREAM_SKIP_UINT16(p); // skip ts LSB halfword
|
|
STREAM_SKIP_UINT16(p); // skip ts MSB halfword
|
|
}
|
|
STREAM_SKIP_UINT16(p); // skip seq_nb
|
|
|
|
uint16_t msg_data_len;
|
|
STREAM_TO_UINT16(msg_data_len, p);
|
|
ASSERT_EQ(msg_data_len, data_len);
|
|
})
|
|
.RetiresOnSaturation();
|
|
|
|
std::vector<uint8_t> data_vec(data_len, 0);
|
|
IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SendIsoDataBigValid) {
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
|
|
for (auto& handle : volatile_test_big_params_evt_.conn_handles) {
|
|
IsoManager::GetInstance()->SetupIsoDataPath(handle,
|
|
kDefaultIsoDataPathParams);
|
|
for (uint8_t num_pkts = 2; num_pkts != 0; num_pkts--) {
|
|
constexpr uint8_t data_len = 108;
|
|
|
|
EXPECT_CALL(bte_interface_, HciSend)
|
|
.WillOnce([handle, data_len](BT_HDR* p_msg, uint16_t event) {
|
|
uint8_t* p = p_msg->data;
|
|
uint16_t msg_handle;
|
|
uint16_t iso_load_len;
|
|
|
|
ASSERT_TRUE((event & MSG_STACK_TO_HC_HCI_ISO) != 0);
|
|
ASSERT_NE(p_msg, nullptr);
|
|
ASSERT_EQ(p_msg->len, data_len + ((p_msg->layer_specific &
|
|
BT_ISO_HDR_CONTAINS_TS)
|
|
? 12
|
|
: 8));
|
|
|
|
// Verify packet internals
|
|
STREAM_TO_UINT16(msg_handle, p);
|
|
ASSERT_EQ(msg_handle, handle);
|
|
|
|
STREAM_TO_UINT16(iso_load_len, p);
|
|
ASSERT_EQ(
|
|
iso_load_len,
|
|
data_len +
|
|
((p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) ? 8 : 4));
|
|
|
|
uint16_t msg_data_len;
|
|
uint16_t msg_dummy;
|
|
if (p_msg->layer_specific & BT_ISO_HDR_CONTAINS_TS) {
|
|
STREAM_TO_UINT16(msg_dummy, p); // skip ts LSB halfword
|
|
STREAM_TO_UINT16(msg_dummy, p); // skip ts MSB halfword
|
|
}
|
|
STREAM_TO_UINT16(msg_dummy, p); // skip seq_nb
|
|
|
|
STREAM_TO_UINT16(msg_data_len, p);
|
|
ASSERT_EQ(msg_data_len, data_len);
|
|
})
|
|
.RetiresOnSaturation();
|
|
|
|
std::vector<uint8_t> data_vec(data_len, 0);
|
|
IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SendIsoDataNoCredits) {
|
|
uint8_t num_buffers = controller_interface_.GetIsoBufferCount();
|
|
std::vector<uint8_t> data_vec(108, 0);
|
|
|
|
// Check on CIG
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
IsoManager::GetInstance()->SetupIsoDataPath(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0],
|
|
kDefaultIsoDataPathParams);
|
|
|
|
/* Try sending twice as much data as we can ignoring the credit limits and
|
|
* expect the redundant packets to be ignored and not propagated down to the
|
|
* HCI.
|
|
*/
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
|
|
// Return all credits for this one handle
|
|
uint8_t mock_rsp[5];
|
|
uint8_t* p = mock_rsp;
|
|
UINT8_TO_STREAM(p, 1);
|
|
UINT16_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles[0]);
|
|
UINT16_TO_STREAM(p, num_buffers);
|
|
IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp));
|
|
|
|
// Check on BIG
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
IsoManager::GetInstance()->SetupIsoDataPath(
|
|
volatile_test_big_params_evt_.conn_handles[0], kDefaultIsoDataPathParams);
|
|
|
|
/* Try sending twice as much data as we can ignoring the credit limits and
|
|
* expect the redundant packets to be ignored and not propagated down to the
|
|
* HCI.
|
|
*/
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers);
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_big_params_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, SendIsoDataCreditsReturned) {
|
|
uint8_t num_buffers = controller_interface_.GetIsoBufferCount();
|
|
std::vector<uint8_t> data_vec(108, 0);
|
|
|
|
// Check on CIG
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
IsoManager::GetInstance()->SetupIsoDataPath(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0],
|
|
kDefaultIsoDataPathParams);
|
|
|
|
/* Try sending twice as much data as we can, ignoring the credits limit and
|
|
* expect the redundant packets to be ignored and not propagated down to the
|
|
* HCI.
|
|
*/
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
|
|
// Return all credits for this one handle
|
|
uint8_t mock_rsp[5];
|
|
uint8_t* p = mock_rsp;
|
|
UINT8_TO_STREAM(p, 1);
|
|
UINT16_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles[0]);
|
|
UINT16_TO_STREAM(p, num_buffers);
|
|
IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp));
|
|
|
|
// Expect some more events go down the HCI
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
|
|
// Return all credits for this one handle
|
|
p = mock_rsp;
|
|
UINT8_TO_STREAM(p, 1);
|
|
UINT16_TO_STREAM(p, volatile_test_cig_create_cmpl_evt_.conn_handles[0]);
|
|
UINT16_TO_STREAM(p, num_buffers);
|
|
IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp));
|
|
|
|
// Check on BIG
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
IsoManager::GetInstance()->SetupIsoDataPath(
|
|
volatile_test_big_params_evt_.conn_handles[0], kDefaultIsoDataPathParams);
|
|
|
|
/* Try sending twice as much data as we can, ignoring the credits limit and
|
|
* expect the redundant packets to be ignored and not propagated down to the
|
|
* HCI.
|
|
*/
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_big_params_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
|
|
// Return all credits for this one handle
|
|
p = mock_rsp;
|
|
UINT8_TO_STREAM(p, 1);
|
|
UINT16_TO_STREAM(p, volatile_test_big_params_evt_.conn_handles[0]);
|
|
UINT16_TO_STREAM(p, num_buffers);
|
|
IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp));
|
|
|
|
// Expect some more events go down the HCI
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(num_buffers).RetiresOnSaturation();
|
|
for (uint8_t i = 0; i < (2 * num_buffers); i++) {
|
|
IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_big_params_evt_.conn_handles[0], data_vec.data(),
|
|
data_vec.size());
|
|
}
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, SendIsoDataWithNoDataPath) {
|
|
std::vector<uint8_t> data_vec(108, 0);
|
|
|
|
// Check on CIG
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
bluetooth::hci::iso_manager::cis_establish_params params;
|
|
for (auto& conn_handle : volatile_test_cig_create_cmpl_evt_.conn_handles) {
|
|
params.conn_pairs.push_back({conn_handle, 1});
|
|
}
|
|
IsoManager::GetInstance()->EstablishCis(params);
|
|
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(0);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_cig_create_cmpl_evt_.conn_handles[0],
|
|
data_vec.data(), data_vec.size()),
|
|
::testing::KilledBySignal(SIGABRT), "Data path not set");
|
|
|
|
// Check on BIG
|
|
IsoManager::GetInstance()->CreateBig(volatile_test_big_params_evt_.big_id,
|
|
kDefaultBigParams);
|
|
|
|
EXPECT_CALL(bte_interface_, HciSend).Times(0);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(
|
|
volatile_test_big_params_evt_.conn_handles[0],
|
|
data_vec.data(), data_vec.size()),
|
|
::testing::KilledBySignal(SIGABRT), "Data path not set");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, SendIsoDataWithNoCigBigHandle) {
|
|
std::vector<uint8_t> data_vec(108, 0);
|
|
ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(134, data_vec.data(),
|
|
data_vec.size()),
|
|
::testing::KilledBySignal(SIGABRT), "No such iso");
|
|
}
|
|
|
|
TEST_F(IsoManagerDeathTest, SendIsoDataWithNoCigConnected) {
|
|
std::vector<uint8_t> data_vec(108, 0);
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(),
|
|
data_vec.size()),
|
|
::testing::KilledBySignal(SIGABRT), "CIS not established");
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, HandleDisconnectNoSuchHandle) {
|
|
// Don't expect any callbacks when connection handle is not for ISO.
|
|
EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
|
|
EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
|
|
|
|
IsoManager::GetInstance()->HandleDisconnect(123, 16);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, HandleDisconnectValidCig) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
|
|
EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
|
|
|
|
// Expect disconnect event exactly once
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent)
|
|
.WillOnce([this, handle](uint8_t event_code, void* data) {
|
|
ASSERT_EQ(event_code,
|
|
bluetooth::hci::iso_manager::kIsoEventCisDisconnected);
|
|
auto* event =
|
|
static_cast<bluetooth::hci::iso_manager::cis_disconnected_evt*>(
|
|
data);
|
|
ASSERT_EQ(event->reason, 16);
|
|
ASSERT_EQ(event->cig_id, volatile_test_cig_create_cmpl_evt_.cig_id);
|
|
ASSERT_EQ(event->cis_conn_hdl, handle);
|
|
});
|
|
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 16);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, HandleDisconnectDisconnectedCig) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
EXPECT_CALL(*big_callbacks_, OnBigEvent).Times(0);
|
|
EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
|
|
|
|
// Expect disconnect event exactly once
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDisconnected, _))
|
|
.Times(1)
|
|
.RetiresOnSaturation();
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 16);
|
|
|
|
// This one was once connected - expect no events
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 16);
|
|
|
|
// This one was never connected - expect no events
|
|
handle = volatile_test_cig_create_cmpl_evt_.conn_handles[1];
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 16);
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, HandleIsoData) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
|
|
.Times(1);
|
|
|
|
std::vector<uint8_t> dummy_msg(18);
|
|
uint8_t* p = dummy_msg.data();
|
|
UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
|
|
UINT16_TO_STREAM(p, 10); // .len
|
|
UINT16_TO_STREAM(p, 0); // .offset
|
|
UINT16_TO_STREAM(p, 0); // .layer_specific
|
|
UINT16_TO_STREAM(p, handle);
|
|
IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
|
|
}
|
|
|
|
/* This test case simulates HCI thread scheduling events on the main thread,
|
|
* without knowing the we are already shutting down the stack and Iso Manager
|
|
* is already stopped.
|
|
*/
|
|
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleIsoData) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
// Stop iso manager before trying to call the HCI callbacks
|
|
IsoManager::GetInstance()->Stop();
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
|
|
.Times(0);
|
|
|
|
// Expect no assert on this call - should be gracefully ignored
|
|
std::vector<uint8_t> dummy_msg(18);
|
|
uint8_t* p = dummy_msg.data();
|
|
UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
|
|
UINT16_TO_STREAM(p, 10); // .len
|
|
UINT16_TO_STREAM(p, 0); // .offset
|
|
UINT16_TO_STREAM(p, 0); // .layer_specific
|
|
UINT16_TO_STREAM(p, handle);
|
|
IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
|
|
}
|
|
|
|
/* This test case simulates HCI thread scheduling events on the main thread,
|
|
* without knowing the we are already shutting down the stack and Iso Manager
|
|
* is already stopped.
|
|
*/
|
|
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleDisconnect) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
// Stop iso manager before trying to call the HCI callbacks
|
|
IsoManager::GetInstance()->Stop();
|
|
|
|
// Expect no event when callback is being called on a stopped iso manager
|
|
EXPECT_CALL(*cig_callbacks_, OnCisEvent).Times(0);
|
|
// Expect no assert on this call - should be gracefully ignored
|
|
IsoManager::GetInstance()->HandleDisconnect(handle, 16);
|
|
}
|
|
|
|
/* This test case simulates HCI thread scheduling events on the main thread,
|
|
* without knowing the we are already shutting down the stack and Iso Manager
|
|
* is already stopped.
|
|
*/
|
|
TEST_F(IsoManagerDeathTestNoCleanup,
|
|
HandleLateArivingEventHandleNumComplDataPkts) {
|
|
uint8_t num_buffers = controller_interface_.GetIsoBufferCount();
|
|
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
// Stop iso manager before trying to call the HCI callbacks
|
|
IsoManager::GetInstance()->Stop();
|
|
|
|
// Expect no assert on this call - should be gracefully ignored
|
|
uint8_t mock_rsp[5];
|
|
uint8_t* p = mock_rsp;
|
|
UINT8_TO_STREAM(p, 1);
|
|
UINT16_TO_STREAM(p, handle);
|
|
UINT16_TO_STREAM(p, num_buffers);
|
|
IsoManager::GetInstance()->HandleNumComplDataPkts(mock_rsp, sizeof(mock_rsp));
|
|
}
|
|
|
|
/* This test case simulates HCI thread scheduling events on the main thread,
|
|
* without knowing the we are already shutting down the stack and Iso Manager
|
|
* is already stopped.
|
|
*/
|
|
TEST_F(IsoManagerDeathTestNoCleanup, HandleLateArivingEventHandleHciEvent) {
|
|
const uint8_t big_id = 0x22;
|
|
|
|
IsoManager::GetInstance()->CreateBig(big_id, kDefaultBigParams);
|
|
|
|
// Stop iso manager before trying to call the HCI callbacks
|
|
IsoManager::GetInstance()->Stop();
|
|
EXPECT_CALL(
|
|
*big_callbacks_,
|
|
OnBigEvent(bluetooth::hci::iso_manager::kIsoEventBigOnTerminateCmpl, _))
|
|
.Times(0);
|
|
|
|
// Expect no assert on this call - should be gracefully ignored
|
|
std::vector<uint8_t> buf(2);
|
|
uint8_t* p = buf.data();
|
|
UINT8_TO_STREAM(p, big_id);
|
|
UINT8_TO_STREAM(p, 16); // Terminated by local host
|
|
IsoManager::GetInstance()->HandleHciEvent(HCI_BLE_TERM_BIG_CPL_EVT,
|
|
buf.data(), buf.size());
|
|
}
|
|
|
|
TEST_F(IsoManagerTest, HandleIsoDataSameSeqNb) {
|
|
IsoManager::GetInstance()->CreateCig(
|
|
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
|
|
|
|
auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
|
|
IsoManager::GetInstance()->EstablishCis({{{handle, 1}}});
|
|
|
|
EXPECT_CALL(
|
|
*cig_callbacks_,
|
|
OnCisEvent(bluetooth::hci::iso_manager::kIsoEventCisDataAvailable, _))
|
|
.Times(2);
|
|
|
|
std::vector<uint8_t> dummy_msg(18);
|
|
uint8_t* p = dummy_msg.data();
|
|
UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_ISO);
|
|
UINT16_TO_STREAM(p, 10); // .len
|
|
UINT16_TO_STREAM(p, 0); // .offset
|
|
UINT16_TO_STREAM(p, 0); // .layer_specific
|
|
UINT16_TO_STREAM(p, handle);
|
|
|
|
IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
|
|
IsoManager::GetInstance()->HandleIsoData(dummy_msg.data());
|
|
}
|