1342 lines
57 KiB
C++
1342 lines
57 KiB
C++
/*
|
|
* Copyright 2019 The Android Open Source Project
|
|
*
|
|
* 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 "hci/acl_manager.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <future>
|
|
#include <map>
|
|
|
|
#include "common/bind.h"
|
|
#include "hci/address.h"
|
|
#include "hci/class_of_device.h"
|
|
#include "hci/controller.h"
|
|
#include "hci/hci_layer.h"
|
|
#include "hci/hci_layer_fake.h"
|
|
#include "os/thread.h"
|
|
#include "packet/raw_builder.h"
|
|
|
|
namespace bluetooth {
|
|
namespace hci {
|
|
namespace acl_manager {
|
|
namespace {
|
|
|
|
using common::BidiQueue;
|
|
using common::BidiQueueEnd;
|
|
using packet::kLittleEndian;
|
|
using packet::PacketView;
|
|
using packet::RawBuilder;
|
|
|
|
constexpr auto kTimeout = std::chrono::seconds(2);
|
|
constexpr auto kShortTimeout = std::chrono::milliseconds(100);
|
|
constexpr uint16_t kScanIntervalFast = 0x0060;
|
|
constexpr uint16_t kScanWindowFast = 0x0030;
|
|
constexpr uint16_t kScanIntervalSlow = 0x0800;
|
|
constexpr uint16_t kScanWindowSlow = 0x0030;
|
|
const AddressWithType empty_address_with_type = hci::AddressWithType();
|
|
|
|
class TestController : public Controller {
|
|
public:
|
|
void RegisterCompletedAclPacketsCallback(
|
|
common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> cb) override {
|
|
acl_cb_ = cb;
|
|
}
|
|
|
|
void UnregisterCompletedAclPacketsCallback() override {
|
|
acl_cb_ = {};
|
|
}
|
|
|
|
uint16_t GetAclPacketLength() const override {
|
|
return acl_buffer_length_;
|
|
}
|
|
|
|
uint16_t GetNumAclPacketBuffers() const override {
|
|
return total_acl_buffers_;
|
|
}
|
|
|
|
bool IsSupported(bluetooth::hci::OpCode op_code) const override {
|
|
return false;
|
|
}
|
|
|
|
LeBufferSize GetLeBufferSize() const override {
|
|
LeBufferSize le_buffer_size;
|
|
le_buffer_size.total_num_le_packets_ = 2;
|
|
le_buffer_size.le_data_packet_length_ = 32;
|
|
return le_buffer_size;
|
|
}
|
|
|
|
void CompletePackets(uint16_t handle, uint16_t packets) {
|
|
acl_cb_.Invoke(handle, packets);
|
|
}
|
|
|
|
uint16_t acl_buffer_length_ = 1024;
|
|
uint16_t total_acl_buffers_ = 2;
|
|
common::ContextualCallback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
|
|
|
|
protected:
|
|
void Start() override {}
|
|
void Stop() override {}
|
|
void ListDependencies(ModuleList* list) const {}
|
|
};
|
|
|
|
class AclManagerNoCallbacksTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
|
|
test_controller_ = new TestController;
|
|
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
|
|
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
|
|
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
|
|
ASSERT_NE(client_handler_, nullptr);
|
|
fake_registry_.Start<AclManager>(&thread_);
|
|
acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
|
|
Address::FromString("A1:A2:A3:A4:A5:A6", remote);
|
|
|
|
hci::Address address;
|
|
Address::FromString("D0:05:04:03:02:01", address);
|
|
hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000);
|
|
auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000);
|
|
acl_manager_->SetPrivacyPolicyForInitiatorAddress(
|
|
LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS,
|
|
address_with_type,
|
|
minimum_rotation_time,
|
|
maximum_rotation_time);
|
|
|
|
auto set_random_address_packet =
|
|
LeSetRandomAddressView::Create(LeAdvertisingCommandView::Create(
|
|
GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS)));
|
|
ASSERT_TRUE(set_random_address_packet.IsValid());
|
|
my_initiating_address = AddressWithType(
|
|
set_random_address_packet.GetRandomAddress(), AddressType::RANDOM_DEVICE_ADDRESS);
|
|
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
}
|
|
|
|
void TearDown() override {
|
|
// Invalid mutex exception is raised if the connections
|
|
// are cleared after the AclConnectionInterface is deleted
|
|
// through fake_registry_.
|
|
mock_connection_callback_.Clear();
|
|
mock_le_connection_callbacks_.Clear();
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.StopAll();
|
|
}
|
|
|
|
void sync_client_handler() {
|
|
ASSERT(thread_.GetReactor()->WaitForIdle(std::chrono::seconds(2)));
|
|
}
|
|
|
|
TestModuleRegistry fake_registry_;
|
|
TestHciLayer* test_hci_layer_ = nullptr;
|
|
TestController* test_controller_ = nullptr;
|
|
os::Thread& thread_ = fake_registry_.GetTestThread();
|
|
AclManager* acl_manager_ = nullptr;
|
|
os::Handler* client_handler_ = nullptr;
|
|
Address remote;
|
|
AddressWithType my_initiating_address;
|
|
const bool use_connect_list_ = true; // gd currently only supports connect list
|
|
|
|
std::future<void> GetConnectionFuture() {
|
|
ASSERT_LOG(mock_connection_callback_.connection_promise_ == nullptr, "Promises promises ... Only one at a time");
|
|
mock_connection_callback_.connection_promise_ = std::make_unique<std::promise<void>>();
|
|
return mock_connection_callback_.connection_promise_->get_future();
|
|
}
|
|
|
|
std::future<void> GetLeConnectionFuture() {
|
|
ASSERT_LOG(mock_le_connection_callbacks_.le_connection_promise_ == nullptr,
|
|
"Promises promises ... Only one at a time");
|
|
mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
|
|
return mock_le_connection_callbacks_.le_connection_promise_->get_future();
|
|
}
|
|
|
|
std::shared_ptr<ClassicAclConnection> GetLastConnection() {
|
|
return mock_connection_callback_.connections_.back();
|
|
}
|
|
|
|
std::shared_ptr<LeAclConnection> GetLastLeConnection() {
|
|
return mock_le_connection_callbacks_.le_connections_.back();
|
|
}
|
|
|
|
void SendAclData(uint16_t handle, AclConnection::QueueUpEnd* queue_end) {
|
|
std::promise<void> promise;
|
|
auto future = promise.get_future();
|
|
queue_end->RegisterEnqueue(client_handler_,
|
|
common::Bind(
|
|
[](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
|
|
queue_end->UnregisterEnqueue();
|
|
promise.set_value();
|
|
return NextPayload(handle);
|
|
},
|
|
queue_end, handle, common::Passed(std::move(promise))));
|
|
auto status = future.wait_for(kTimeout);
|
|
ASSERT_EQ(status, std::future_status::ready);
|
|
}
|
|
|
|
ConnectionManagementCommandView GetConnectionManagementCommand(OpCode op_code) {
|
|
auto base_command = test_hci_layer_->GetCommand();
|
|
ConnectionManagementCommandView command =
|
|
ConnectionManagementCommandView::Create(AclCommandView::Create(base_command));
|
|
EXPECT_TRUE(command.IsValid());
|
|
EXPECT_EQ(command.GetOpCode(), op_code);
|
|
return command;
|
|
}
|
|
|
|
class MockConnectionCallback : public ConnectionCallbacks {
|
|
public:
|
|
void OnConnectSuccess(std::unique_ptr<ClassicAclConnection> connection) override {
|
|
// Convert to std::shared_ptr during push_back()
|
|
connections_.push_back(std::move(connection));
|
|
if (connection_promise_ != nullptr) {
|
|
connection_promise_->set_value();
|
|
connection_promise_.reset();
|
|
}
|
|
}
|
|
|
|
void Clear() {
|
|
connections_.clear();
|
|
}
|
|
|
|
MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
|
|
|
|
MOCK_METHOD(void, HACK_OnEscoConnectRequest, (Address, ClassOfDevice), (override));
|
|
MOCK_METHOD(void, HACK_OnScoConnectRequest, (Address, ClassOfDevice), (override));
|
|
|
|
std::list<std::shared_ptr<ClassicAclConnection>> connections_;
|
|
std::unique_ptr<std::promise<void>> connection_promise_;
|
|
} mock_connection_callback_;
|
|
|
|
class MockLeConnectionCallbacks : public LeConnectionCallbacks {
|
|
public:
|
|
void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<LeAclConnection> connection) override {
|
|
le_connections_.push_back(std::move(connection));
|
|
if (le_connection_promise_ != nullptr) {
|
|
le_connection_promise_->set_value();
|
|
le_connection_promise_.reset();
|
|
}
|
|
}
|
|
|
|
void Clear() {
|
|
le_connections_.clear();
|
|
}
|
|
|
|
MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
|
|
|
|
std::list<std::shared_ptr<LeAclConnection>> le_connections_;
|
|
std::unique_ptr<std::promise<void>> le_connection_promise_;
|
|
} mock_le_connection_callbacks_;
|
|
};
|
|
|
|
class AclManagerTest : public AclManagerNoCallbacksTest {
|
|
protected:
|
|
void SetUp() override {
|
|
AclManagerNoCallbacksTest::SetUp();
|
|
acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
|
|
acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
|
|
}
|
|
};
|
|
|
|
class AclManagerWithConnectionTest : public AclManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
AclManagerTest::SetUp();
|
|
|
|
handle_ = 0x123;
|
|
acl_manager_->CreateConnection(remote);
|
|
|
|
// Wait for the connection request
|
|
auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
while (!last_command.IsValid()) {
|
|
last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
}
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::CENTRAL));
|
|
|
|
auto first_connection = GetConnectionFuture();
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
|
|
|
|
auto first_connection_status = first_connection.wait_for(kTimeout);
|
|
ASSERT_EQ(first_connection_status, std::future_status::ready);
|
|
|
|
connection_ = GetLastConnection();
|
|
connection_->RegisterCallbacks(&mock_connection_management_callbacks_, client_handler_);
|
|
}
|
|
|
|
void TearDown() override {
|
|
// Invalid mutex exception is raised if the connection
|
|
// is cleared after the AclConnectionInterface is deleted
|
|
// through fake_registry_.
|
|
mock_connection_callback_.Clear();
|
|
mock_le_connection_callbacks_.Clear();
|
|
connection_.reset();
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.StopAll();
|
|
}
|
|
|
|
uint16_t handle_;
|
|
std::shared_ptr<ClassicAclConnection> connection_;
|
|
|
|
class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks {
|
|
public:
|
|
MOCK_METHOD1(OnConnectionPacketTypeChanged, void(uint16_t packet_type));
|
|
MOCK_METHOD1(OnAuthenticationComplete, void(hci::ErrorCode hci_status));
|
|
MOCK_METHOD1(OnEncryptionChange, void(EncryptionEnabled enabled));
|
|
MOCK_METHOD0(OnChangeConnectionLinkKeyComplete, void());
|
|
MOCK_METHOD1(OnReadClockOffsetComplete, void(uint16_t clock_offse));
|
|
MOCK_METHOD3(OnModeChange, void(ErrorCode status, Mode current_mode, uint16_t interval));
|
|
MOCK_METHOD5(
|
|
OnSniffSubrating,
|
|
void(
|
|
ErrorCode status,
|
|
uint16_t maximum_transmit_latency,
|
|
uint16_t maximum_receive_latency,
|
|
uint16_t minimum_remote_timeout,
|
|
uint16_t minimum_local_timeout));
|
|
MOCK_METHOD5(OnQosSetupComplete, void(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
|
|
uint32_t latency, uint32_t delay_variation));
|
|
MOCK_METHOD6(OnFlowSpecificationComplete,
|
|
void(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
|
|
uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency));
|
|
MOCK_METHOD0(OnFlushOccurred, void());
|
|
MOCK_METHOD1(OnRoleDiscoveryComplete, void(Role current_role));
|
|
MOCK_METHOD1(OnReadLinkPolicySettingsComplete, void(uint16_t link_policy_settings));
|
|
MOCK_METHOD1(OnReadAutomaticFlushTimeoutComplete, void(uint16_t flush_timeout));
|
|
MOCK_METHOD1(OnReadTransmitPowerLevelComplete, void(uint8_t transmit_power_level));
|
|
MOCK_METHOD1(OnReadLinkSupervisionTimeoutComplete, void(uint16_t link_supervision_timeout));
|
|
MOCK_METHOD1(OnReadFailedContactCounterComplete, void(uint16_t failed_contact_counter));
|
|
MOCK_METHOD1(OnReadLinkQualityComplete, void(uint8_t link_quality));
|
|
MOCK_METHOD2(OnReadAfhChannelMapComplete, void(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map));
|
|
MOCK_METHOD1(OnReadRssiComplete, void(uint8_t rssi));
|
|
MOCK_METHOD2(OnReadClockComplete, void(uint32_t clock, uint16_t accuracy));
|
|
MOCK_METHOD1(OnCentralLinkKeyComplete, void(KeyFlag flag));
|
|
MOCK_METHOD2(OnRoleChange, void(ErrorCode hci_status, Role new_role));
|
|
MOCK_METHOD1(OnDisconnection, void(ErrorCode reason));
|
|
MOCK_METHOD4(
|
|
OnReadRemoteVersionInformationComplete,
|
|
void(hci::ErrorCode hci_status, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version));
|
|
MOCK_METHOD1(OnReadRemoteSupportedFeaturesComplete, void(uint64_t features));
|
|
MOCK_METHOD3(
|
|
OnReadRemoteExtendedFeaturesComplete, void(uint8_t page_number, uint8_t max_page_number, uint64_t features));
|
|
} mock_connection_management_callbacks_;
|
|
};
|
|
|
|
TEST_F(AclManagerTest, startup_teardown) {}
|
|
|
|
TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) {
|
|
uint16_t handle = 1;
|
|
|
|
acl_manager_->CreateConnection(remote);
|
|
|
|
// Wait for the connection request
|
|
auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
while (!last_command.IsValid()) {
|
|
last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
}
|
|
|
|
auto first_connection = GetConnectionFuture();
|
|
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
|
|
|
|
auto first_connection_status = first_connection.wait_for(kTimeout);
|
|
ASSERT_EQ(first_connection_status, std::future_status::ready);
|
|
|
|
auto connection = GetLastConnection();
|
|
ASSERT_EQ(connection->GetAddress(), remote);
|
|
}
|
|
|
|
TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) {
|
|
uint16_t handle = 0x123;
|
|
|
|
acl_manager_->CreateConnection(remote);
|
|
|
|
// Wait for the connection request
|
|
auto last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
while (!last_command.IsValid()) {
|
|
last_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
}
|
|
|
|
EXPECT_CALL(mock_connection_callback_, OnConnectFail(remote, ErrorCode::PAGE_TIMEOUT));
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionCompleteBuilder::Create(ErrorCode::PAGE_TIMEOUT, handle, remote, LinkType::ACL, Enable::DISABLED));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
}
|
|
|
|
class AclManagerWithLeConnectionTest : public AclManagerTest {
|
|
protected:
|
|
void SetUp() override {
|
|
AclManagerTest::SetUp();
|
|
|
|
remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type_, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto le_connection_management_command_view =
|
|
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
if (use_connect_list_) {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), empty_address_with_type.GetAddress());
|
|
ASSERT_EQ(command_view.GetPeerAddressType(), empty_address_with_type.GetAddressType());
|
|
} else {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), remote);
|
|
ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
}
|
|
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
|
|
auto first_connection = GetLeConnectionFuture();
|
|
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
handle_,
|
|
Role::CENTRAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0C80,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
auto first_connection_status = first_connection.wait_for(kTimeout);
|
|
ASSERT_EQ(first_connection_status, std::future_status::ready);
|
|
|
|
connection_ = GetLastLeConnection();
|
|
}
|
|
|
|
void TearDown() override {
|
|
// Invalid mutex exception is raised if the connection
|
|
// is cleared after the AclConnectionInterface is deleted
|
|
// through fake_registry_.
|
|
mock_connection_callback_.Clear();
|
|
mock_le_connection_callbacks_.Clear();
|
|
connection_.reset();
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.StopAll();
|
|
}
|
|
|
|
uint16_t handle_ = 0x123;
|
|
std::shared_ptr<LeAclConnection> connection_;
|
|
AddressWithType remote_with_type_;
|
|
|
|
class MockLeConnectionManagementCallbacks : public LeConnectionManagementCallbacks {
|
|
public:
|
|
MOCK_METHOD1(OnDisconnection, void(ErrorCode reason));
|
|
MOCK_METHOD4(
|
|
OnConnectionUpdate,
|
|
void(
|
|
hci::ErrorCode hci_status,
|
|
uint16_t connection_interval,
|
|
uint16_t connection_latency,
|
|
uint16_t supervision_timeout));
|
|
MOCK_METHOD4(OnDataLengthChange, void(uint16_t tx_octets, uint16_t tx_time, uint16_t rx_octets, uint16_t rx_time));
|
|
MOCK_METHOD4(
|
|
OnReadRemoteVersionInformationComplete,
|
|
void(hci::ErrorCode hci_status, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version));
|
|
MOCK_METHOD2(OnLeReadRemoteFeaturesComplete, void(hci::ErrorCode hci_status, uint64_t features));
|
|
MOCK_METHOD3(OnPhyUpdate, void(hci::ErrorCode hci_status, uint8_t tx_phy, uint8_t rx_phy));
|
|
MOCK_METHOD1(OnLocalAddressUpdate, void(AddressWithType address_with_type));
|
|
} mock_le_connection_management_callbacks_;
|
|
};
|
|
|
|
// TODO: implement version of this test where controller supports Extended Advertising Feature in
|
|
// GetLeLocalSupportedFeatures, and LE Extended Create Connection is used
|
|
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_connection_complete_success) {
|
|
ASSERT_EQ(connection_->GetLocalAddress(), my_initiating_address);
|
|
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
|
|
}
|
|
|
|
TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto le_connection_management_command_view =
|
|
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
if (use_connect_list_) {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), hci::Address::kEmpty);
|
|
} else {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), remote);
|
|
}
|
|
EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
|
|
EXPECT_CALL(mock_le_connection_callbacks_,
|
|
OnLeConnectFail(remote_with_type, ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES));
|
|
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES,
|
|
0x123,
|
|
Role::CENTRAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0011,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
|
|
le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(remove_command_view.IsValid());
|
|
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
}
|
|
|
|
TEST_F(AclManagerTest, cancel_le_connection) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
|
|
acl_manager_->CancelLeConnect(remote_with_type);
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
|
|
auto le_connection_management_command_view =
|
|
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto command_view = LeCreateConnectionCancelView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::UNKNOWN_CONNECTION,
|
|
0x123,
|
|
Role::CENTRAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0011,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
packet = GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
|
|
le_connection_management_command_view = LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto remove_command_view = LeRemoveDeviceFromFilterAcceptListView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(remove_command_view.IsValid());
|
|
|
|
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
}
|
|
|
|
TEST_F(AclManagerTest, create_connection_with_fast_mode) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(
|
|
LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto command_view =
|
|
LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalFast);
|
|
ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowFast);
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
|
|
auto first_connection = GetLeConnectionFuture();
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
0x00,
|
|
Role::CENTRAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0C80,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
auto first_connection_status = first_connection.wait_for(kTimeout);
|
|
ASSERT_EQ(first_connection_status, std::future_status::ready);
|
|
}
|
|
|
|
TEST_F(AclManagerTest, create_connection_with_slow_mode) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, false);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto command_view =
|
|
LeCreateConnectionView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetLeScanInterval(), kScanIntervalSlow);
|
|
ASSERT_EQ(command_view.GetLeScanWindow(), kScanWindowSlow);
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
auto first_connection = GetLeConnectionFuture();
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
0x00,
|
|
Role::CENTRAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0C80,
|
|
ClockAccuracy::PPM_30));
|
|
GetConnectionManagementCommand(OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
auto first_connection_status = first_connection.wait_for(kTimeout);
|
|
ASSERT_EQ(first_connection_status, std::future_status::ready);
|
|
}
|
|
|
|
TEST_F(AclManagerWithLeConnectionTest, acl_send_data_one_le_connection) {
|
|
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
|
|
ASSERT_EQ(connection_->GetHandle(), handle_);
|
|
|
|
// Send a packet from HCI
|
|
test_hci_layer_->IncomingAclData(handle_);
|
|
auto queue_end = connection_->GetAclQueueEnd();
|
|
|
|
std::unique_ptr<PacketView<kLittleEndian>> received;
|
|
do {
|
|
received = queue_end->TryDequeue();
|
|
} while (received == nullptr);
|
|
|
|
PacketView<kLittleEndian> received_packet = *received;
|
|
|
|
// Send a packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
auto sent_packet = test_hci_layer_->OutgoingAclData();
|
|
|
|
// Send another packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
sent_packet = test_hci_layer_->OutgoingAclData();
|
|
}
|
|
|
|
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_connection_update_success) {
|
|
ASSERT_EQ(connection_->GetLocalAddress(), my_initiating_address);
|
|
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
|
|
ASSERT_EQ(connection_->GetHandle(), handle_);
|
|
connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
|
|
|
|
std::promise<ErrorCode> promise;
|
|
ErrorCode hci_status = hci::ErrorCode::SUCCESS;
|
|
uint16_t connection_interval_min = 0x0012;
|
|
uint16_t connection_interval_max = 0x0080;
|
|
uint16_t connection_interval = (connection_interval_max + connection_interval_min) / 2;
|
|
uint16_t connection_latency = 0x0001;
|
|
uint16_t supervision_timeout = 0x0A00;
|
|
connection_->LeConnectionUpdate(
|
|
connection_interval_min,
|
|
connection_interval_max,
|
|
connection_latency,
|
|
supervision_timeout,
|
|
0x10,
|
|
0x20);
|
|
auto update_packet = GetConnectionManagementCommand(OpCode::LE_CONNECTION_UPDATE);
|
|
auto update_view =
|
|
LeConnectionUpdateView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(update_packet)));
|
|
ASSERT_TRUE(update_view.IsValid());
|
|
EXPECT_EQ(update_view.GetConnectionHandle(), handle_);
|
|
test_hci_layer_->IncomingEvent(LeConnectionUpdateStatusBuilder::Create(ErrorCode::SUCCESS, 0x1));
|
|
EXPECT_CALL(
|
|
mock_le_connection_management_callbacks_,
|
|
OnConnectionUpdate(hci_status, connection_interval, connection_latency, supervision_timeout));
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionUpdateCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS, handle_, connection_interval, connection_latency, supervision_timeout));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect) {
|
|
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
|
|
ASSERT_EQ(connection_->GetHandle(), handle_);
|
|
connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
|
|
|
|
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
|
|
EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
|
|
test_hci_layer_->Disconnect(handle_, reason);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_disconnect_data_race) {
|
|
ASSERT_EQ(connection_->GetRemoteAddress(), remote_with_type_);
|
|
ASSERT_EQ(connection_->GetHandle(), handle_);
|
|
connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
|
|
|
|
test_hci_layer_->IncomingAclData(handle_);
|
|
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
|
|
EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
|
|
test_hci_layer_->Disconnect(handle_, reason);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithLeConnectionTest, invoke_registered_callback_le_queue_disconnect) {
|
|
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
|
|
test_hci_layer_->Disconnect(handle_, reason);
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
|
|
EXPECT_CALL(mock_le_connection_management_callbacks_, OnDisconnection(reason));
|
|
connection_->RegisterCallbacks(&mock_le_connection_management_callbacks_, client_handler_);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, invoke_registered_callback_disconnection_complete) {
|
|
auto reason = ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
|
|
test_hci_layer_->Disconnect(handle_, reason);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, acl_send_data_one_connection) {
|
|
// Send a packet from HCI
|
|
test_hci_layer_->IncomingAclData(handle_);
|
|
auto queue_end = connection_->GetAclQueueEnd();
|
|
|
|
std::unique_ptr<PacketView<kLittleEndian>> received;
|
|
do {
|
|
received = queue_end->TryDequeue();
|
|
} while (received == nullptr);
|
|
|
|
PacketView<kLittleEndian> received_packet = *received;
|
|
|
|
// Send a packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
auto sent_packet = test_hci_layer_->OutgoingAclData();
|
|
|
|
// Send another packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
sent_packet = test_hci_layer_->OutgoingAclData();
|
|
auto reason = ErrorCode::AUTHENTICATION_FAILURE;
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnDisconnection(reason));
|
|
connection_->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
|
|
auto packet = GetConnectionManagementCommand(OpCode::DISCONNECT);
|
|
auto command_view = DisconnectView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetConnectionHandle(), handle_);
|
|
test_hci_layer_->Disconnect(handle_, reason);
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, acl_send_data_credits) {
|
|
// Use all the credits
|
|
for (uint16_t credits = 0; credits < test_controller_->total_acl_buffers_; credits++) {
|
|
// Send a packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
auto sent_packet = test_hci_layer_->OutgoingAclData();
|
|
}
|
|
|
|
// Send another packet from the connection
|
|
SendAclData(handle_, connection_->GetAclQueueEnd());
|
|
|
|
test_hci_layer_->AssertNoOutgoingAclData();
|
|
|
|
test_controller_->CompletePackets(handle_, 1);
|
|
|
|
auto after_credits_sent_packet = test_hci_layer_->OutgoingAclData();
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_switch_role) {
|
|
acl_manager_->SwitchRole(connection_->GetAddress(), Role::PERIPHERAL);
|
|
auto packet = GetConnectionManagementCommand(OpCode::SWITCH_ROLE);
|
|
auto command_view = SwitchRoleView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetBdAddr(), connection_->GetAddress());
|
|
ASSERT_EQ(command_view.GetRole(), Role::PERIPHERAL);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleChange(hci::ErrorCode::SUCCESS, Role::PERIPHERAL));
|
|
test_hci_layer_->IncomingEvent(
|
|
RoleChangeBuilder::Create(ErrorCode::SUCCESS, connection_->GetAddress(), Role::PERIPHERAL));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_write_default_link_policy_settings) {
|
|
uint16_t link_policy_settings = 0x05;
|
|
acl_manager_->WriteDefaultLinkPolicySettings(link_policy_settings);
|
|
auto packet = GetConnectionManagementCommand(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
|
|
auto command_view = WriteDefaultLinkPolicySettingsView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetDefaultLinkPolicySettings(), 0x05);
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
WriteDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS));
|
|
sync_client_handler();
|
|
|
|
ASSERT_EQ(link_policy_settings, acl_manager_->ReadDefaultLinkPolicySettings());
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_authentication_requested) {
|
|
connection_->AuthenticationRequested();
|
|
auto packet = GetConnectionManagementCommand(OpCode::AUTHENTICATION_REQUESTED);
|
|
auto command_view = AuthenticationRequestedView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnAuthenticationComplete);
|
|
test_hci_layer_->IncomingEvent(
|
|
AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) {
|
|
connection_->ReadClockOffset();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK_OFFSET);
|
|
auto command_view = ReadClockOffsetView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockOffsetComplete(0x0123));
|
|
test_hci_layer_->IncomingEvent(
|
|
ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_hold_mode) {
|
|
connection_->HoldMode(0x0500, 0x0020);
|
|
auto packet = GetConnectionManagementCommand(OpCode::HOLD_MODE);
|
|
auto command_view = HoldModeView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetHoldModeMaxInterval(), 0x0500);
|
|
ASSERT_EQ(command_view.GetHoldModeMinInterval(), 0x0020);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::HOLD, 0x0020));
|
|
test_hci_layer_->IncomingEvent(
|
|
ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_sniff_mode) {
|
|
connection_->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
|
|
auto packet = GetConnectionManagementCommand(OpCode::SNIFF_MODE);
|
|
auto command_view = SniffModeView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetSniffMaxInterval(), 0x0500);
|
|
ASSERT_EQ(command_view.GetSniffMinInterval(), 0x0020);
|
|
ASSERT_EQ(command_view.GetSniffAttempt(), 0x0040);
|
|
ASSERT_EQ(command_view.GetSniffTimeout(), 0x0014);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::SNIFF, 0x0028));
|
|
test_hci_layer_->IncomingEvent(
|
|
ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_exit_sniff_mode) {
|
|
connection_->ExitSniffMode();
|
|
auto packet = GetConnectionManagementCommand(OpCode::EXIT_SNIFF_MODE);
|
|
auto command_view = ExitSniffModeView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(ErrorCode::SUCCESS, Mode::ACTIVE, 0x00));
|
|
test_hci_layer_->IncomingEvent(
|
|
ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_qos_setup) {
|
|
connection_->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
|
|
auto packet = GetConnectionManagementCommand(OpCode::QOS_SETUP);
|
|
auto command_view = QosSetupView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
|
|
ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
|
|
ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1233u);
|
|
ASSERT_EQ(command_view.GetLatency(), 0x1232u);
|
|
ASSERT_EQ(command_view.GetDelayVariation(), 0x1231u);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_,
|
|
OnQosSetupComplete(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
|
|
test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_flow_specification) {
|
|
connection_->FlowSpecification(
|
|
FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
|
|
auto packet = GetConnectionManagementCommand(OpCode::FLOW_SPECIFICATION);
|
|
auto command_view = FlowSpecificationView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetFlowDirection(), FlowDirection::OUTGOING_FLOW);
|
|
ASSERT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
|
|
ASSERT_EQ(command_view.GetTokenRate(), 0x1234u);
|
|
ASSERT_EQ(command_view.GetTokenBucketSize(), 0x1233u);
|
|
ASSERT_EQ(command_view.GetPeakBandwidth(), 0x1232u);
|
|
ASSERT_EQ(command_view.GetAccessLatency(), 0x1231u);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_,
|
|
OnFlowSpecificationComplete(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
|
|
0x1232, 0x1231));
|
|
test_hci_layer_->IncomingEvent(FlowSpecificationCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
handle_,
|
|
FlowDirection::OUTGOING_FLOW,
|
|
ServiceType::BEST_EFFORT,
|
|
0x1234,
|
|
0x1233,
|
|
0x1232,
|
|
0x1231));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_flush) {
|
|
connection_->Flush();
|
|
auto packet = GetConnectionManagementCommand(OpCode::FLUSH);
|
|
auto command_view = FlushView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnFlushOccurred());
|
|
test_hci_layer_->IncomingEvent(FlushOccurredBuilder::Create(handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_role_discovery) {
|
|
connection_->RoleDiscovery();
|
|
auto packet = GetConnectionManagementCommand(OpCode::ROLE_DISCOVERY);
|
|
auto command_view = RoleDiscoveryView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnRoleDiscoveryComplete(Role::CENTRAL));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(RoleDiscoveryCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, Role::CENTRAL));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_link_policy_settings) {
|
|
connection_->ReadLinkPolicySettings();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_POLICY_SETTINGS);
|
|
auto command_view = ReadLinkPolicySettingsView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkPolicySettingsComplete(0x07));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadLinkPolicySettingsCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x07));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_write_link_policy_settings) {
|
|
connection_->WriteLinkPolicySettings(0x05);
|
|
auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_POLICY_SETTINGS);
|
|
auto command_view = WriteLinkPolicySettingsView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetLinkPolicySettings(), 0x05);
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
WriteLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_sniff_subrating) {
|
|
connection_->SniffSubrating(0x1234, 0x1235, 0x1236);
|
|
auto packet = GetConnectionManagementCommand(OpCode::SNIFF_SUBRATING);
|
|
auto command_view = SniffSubratingView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetMaximumLatency(), 0x1234);
|
|
ASSERT_EQ(command_view.GetMinimumRemoteTimeout(), 0x1235);
|
|
ASSERT_EQ(command_view.GetMinimumLocalTimeout(), 0x1236);
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_automatic_flush_timeout) {
|
|
connection_->ReadAutomaticFlushTimeout();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
|
|
auto command_view = ReadAutomaticFlushTimeoutView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadAutomaticFlushTimeoutComplete(0x07ff));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadAutomaticFlushTimeoutCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_write_automatic_flush_timeout) {
|
|
connection_->WriteAutomaticFlushTimeout(0x07FF);
|
|
auto packet = GetConnectionManagementCommand(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
|
|
auto command_view = WriteAutomaticFlushTimeoutView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetFlushTimeout(), 0x07FF);
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
WriteAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_transmit_power_level) {
|
|
connection_->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_TRANSMIT_POWER_LEVEL);
|
|
auto command_view = ReadTransmitPowerLevelView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetTransmitPowerLevelType(), TransmitPowerLevelType::CURRENT);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadTransmitPowerLevelComplete(0x07));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadTransmitPowerLevelCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x07));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_link_supervision_timeout) {
|
|
connection_->ReadLinkSupervisionTimeout();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
|
|
auto command_view = ReadLinkSupervisionTimeoutView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkSupervisionTimeoutComplete(0x5677));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadLinkSupervisionTimeoutCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_write_link_supervision_timeout) {
|
|
connection_->WriteLinkSupervisionTimeout(0x5678);
|
|
auto packet = GetConnectionManagementCommand(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
|
|
auto command_view = WriteLinkSupervisionTimeoutView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetLinkSupervisionTimeout(), 0x5678);
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
WriteLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_failed_contact_counter) {
|
|
connection_->ReadFailedContactCounter();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_FAILED_CONTACT_COUNTER);
|
|
auto command_view = ReadFailedContactCounterView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadFailedContactCounterComplete(0x00));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadFailedContactCounterCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x00));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_reset_failed_contact_counter) {
|
|
connection_->ResetFailedContactCounter();
|
|
auto packet = GetConnectionManagementCommand(OpCode::RESET_FAILED_CONTACT_COUNTER);
|
|
auto command_view = ResetFailedContactCounterView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
ResetFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_link_quality) {
|
|
connection_->ReadLinkQuality();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_LINK_QUALITY);
|
|
auto command_view = ReadLinkQualityView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkQualityComplete(0xa9));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
ReadLinkQualityCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0xa9));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_afh_channel_map) {
|
|
connection_->ReadAfhChannelMap();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_AFH_CHANNEL_MAP);
|
|
auto command_view = ReadAfhChannelMapView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
std::array<uint8_t, 10> afh_channel_map = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_,
|
|
OnReadAfhChannelMapComplete(AfhMode::AFH_ENABLED, afh_channel_map));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, AfhMode::AFH_ENABLED, afh_channel_map));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_rssi) {
|
|
connection_->ReadRssi();
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_RSSI);
|
|
auto command_view = ReadRssiView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
sync_client_handler();
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadRssiComplete(0x00));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(
|
|
ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
|
|
sync_client_handler();
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, send_read_clock) {
|
|
connection_->ReadClock(WhichClock::LOCAL);
|
|
auto packet = GetConnectionManagementCommand(OpCode::READ_CLOCK);
|
|
auto command_view = ReadClockView::Create(packet);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
ASSERT_EQ(command_view.GetWhichClock(), WhichClock::LOCAL);
|
|
|
|
EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockComplete(0x00002e6a, 0x0000));
|
|
uint8_t num_packets = 1;
|
|
test_hci_layer_->IncomingEvent(ReadClockCompleteBuilder::Create(
|
|
num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
|
|
sync_client_handler();
|
|
}
|
|
|
|
class AclManagerWithResolvableAddressTest : public AclManagerNoCallbacksTest {
|
|
protected:
|
|
void SetUp() override {
|
|
test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
|
|
test_controller_ = new TestController;
|
|
fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
|
|
fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
|
|
client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
|
|
ASSERT_NE(client_handler_, nullptr);
|
|
fake_registry_.Start<AclManager>(&thread_);
|
|
acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
|
|
Address::FromString("A1:A2:A3:A4:A5:A6", remote);
|
|
|
|
hci::Address address;
|
|
Address::FromString("D0:05:04:03:02:01", address);
|
|
hci::AddressWithType address_with_type(address, hci::AddressType::RANDOM_DEVICE_ADDRESS);
|
|
acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
|
|
acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
|
|
auto minimum_rotation_time = std::chrono::milliseconds(7 * 60 * 1000);
|
|
auto maximum_rotation_time = std::chrono::milliseconds(15 * 60 * 1000);
|
|
acl_manager_->SetPrivacyPolicyForInitiatorAddress(
|
|
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
|
|
address_with_type,
|
|
minimum_rotation_time,
|
|
maximum_rotation_time);
|
|
|
|
GetConnectionManagementCommand(OpCode::LE_SET_RANDOM_ADDRESS);
|
|
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
}
|
|
};
|
|
|
|
TEST_F(AclManagerWithResolvableAddressTest, create_connection_cancel_fail) {
|
|
auto remote_with_type_ = AddressWithType(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type_, true);
|
|
|
|
// Add device to connect list
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(
|
|
LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
// send create connection command
|
|
GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
test_hci_layer_->IncomingEvent(LeCreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 0x01));
|
|
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
|
|
Address remote2;
|
|
Address::FromString("A1:A2:A3:A4:A5:A7", remote2);
|
|
auto remote_with_type2 = AddressWithType(remote2, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
|
|
// create another connection
|
|
acl_manager_->CreateLeConnection(remote_with_type2, true);
|
|
|
|
// cancel previous connection
|
|
GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION_CANCEL);
|
|
|
|
// receive connection complete of first device
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
0x123,
|
|
Role::PERIPHERAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0011,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
// receive create connection cancel complete with ErrorCode::CONNECTION_ALREADY_EXISTS
|
|
test_hci_layer_->IncomingEvent(
|
|
LeCreateConnectionCancelCompleteBuilder::Create(0x01, ErrorCode::CONNECTION_ALREADY_EXISTS));
|
|
|
|
// Add another device to connect list
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
// Sync events.
|
|
}
|
|
|
|
class AclManagerLifeCycleTest : public AclManagerNoCallbacksTest {
|
|
protected:
|
|
void SetUp() override {
|
|
AclManagerNoCallbacksTest::SetUp();
|
|
acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
|
|
acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
|
|
}
|
|
|
|
AddressWithType remote_with_type_;
|
|
uint16_t handle_{0x123};
|
|
};
|
|
|
|
TEST_F(AclManagerLifeCycleTest, unregister_classic_after_create_connection) {
|
|
// Inject create connection
|
|
acl_manager_->CreateConnection(remote);
|
|
auto connection_command = GetConnectionManagementCommand(OpCode::CREATE_CONNECTION);
|
|
|
|
// Unregister callbacks after sending connection request
|
|
auto promise = std::promise<void>();
|
|
auto future = promise.get_future();
|
|
acl_manager_->UnregisterCallbacks(&mock_connection_callback_, std::move(promise));
|
|
future.get();
|
|
|
|
// Inject peer sending connection complete
|
|
auto connection_future = GetConnectionFuture();
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
|
|
|
|
sync_client_handler();
|
|
auto connection_future_status = connection_future.wait_for(kShortTimeout);
|
|
ASSERT_NE(connection_future_status, std::future_status::ready);
|
|
}
|
|
|
|
TEST_F(AclManagerLifeCycleTest, unregister_le_before_connection_complete) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto le_connection_management_command_view =
|
|
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
if (use_connect_list_) {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), hci::Address::kEmpty);
|
|
} else {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), remote);
|
|
}
|
|
ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
|
|
// Unregister callbacks after sending connection request
|
|
auto promise = std::promise<void>();
|
|
auto future = promise.get_future();
|
|
acl_manager_->UnregisterLeCallbacks(&mock_le_connection_callbacks_, std::move(promise));
|
|
future.get();
|
|
|
|
auto connection_future = GetLeConnectionFuture();
|
|
test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
0x123,
|
|
Role::PERIPHERAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
0x0100,
|
|
0x0010,
|
|
0x0500,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
sync_client_handler();
|
|
auto connection_future_status = connection_future.wait_for(kShortTimeout);
|
|
ASSERT_NE(connection_future_status, std::future_status::ready);
|
|
}
|
|
|
|
TEST_F(AclManagerLifeCycleTest, unregister_le_before_enhanced_connection_complete) {
|
|
AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
acl_manager_->CreateLeConnection(remote_with_type, true);
|
|
GetConnectionManagementCommand(OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST);
|
|
test_hci_layer_->IncomingEvent(LeAddDeviceToFilterAcceptListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
|
|
|
|
auto packet = GetConnectionManagementCommand(OpCode::LE_CREATE_CONNECTION);
|
|
auto le_connection_management_command_view =
|
|
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet));
|
|
auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
|
|
ASSERT_TRUE(command_view.IsValid());
|
|
if (use_connect_list_) {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), hci::Address::kEmpty);
|
|
} else {
|
|
ASSERT_EQ(command_view.GetPeerAddress(), remote);
|
|
}
|
|
ASSERT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
|
|
|
|
// Unregister callbacks after sending connection request
|
|
auto promise = std::promise<void>();
|
|
auto future = promise.get_future();
|
|
acl_manager_->UnregisterLeCallbacks(&mock_le_connection_callbacks_, std::move(promise));
|
|
future.get();
|
|
|
|
auto connection_future = GetLeConnectionFuture();
|
|
test_hci_layer_->IncomingLeMetaEvent(LeEnhancedConnectionCompleteBuilder::Create(
|
|
ErrorCode::SUCCESS,
|
|
0x123,
|
|
Role::PERIPHERAL,
|
|
AddressType::PUBLIC_DEVICE_ADDRESS,
|
|
remote,
|
|
Address::kEmpty,
|
|
Address::kEmpty,
|
|
0x0100,
|
|
0x0010,
|
|
0x0500,
|
|
ClockAccuracy::PPM_30));
|
|
|
|
sync_client_handler();
|
|
auto connection_future_status = connection_future.wait_for(kShortTimeout);
|
|
ASSERT_NE(connection_future_status, std::future_status::ready);
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, remote_sco_connect_request) {
|
|
ClassOfDevice class_of_device;
|
|
|
|
EXPECT_CALL(mock_connection_callback_, HACK_OnScoConnectRequest(remote, class_of_device));
|
|
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::SCO));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
}
|
|
|
|
TEST_F(AclManagerWithConnectionTest, remote_esco_connect_request) {
|
|
ClassOfDevice class_of_device;
|
|
|
|
EXPECT_CALL(mock_connection_callback_, HACK_OnEscoConnectRequest(remote, class_of_device));
|
|
|
|
test_hci_layer_->IncomingEvent(
|
|
ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ESCO));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
|
|
fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace acl_manager
|
|
} // namespace hci
|
|
} // namespace bluetooth
|