blob: cc6c2923d6410aa233ad39ee884e37c632453521 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
anyhow::{format_err, Error},
fidl_fuchsia_bluetooth::Status,
fidl_fuchsia_bluetooth_control::{
AddressType, BondingData, LeData, Ltk, RemoteKey, SecurityProperties,
},
fuchsia_bluetooth::{
expectation,
types::{Address, PeerId},
},
futures::TryFutureExt,
};
use crate::harness::{
emulator::EmulatorHarness,
expect::expect_eq,
host_driver::{expect_peer, HostDriverHarness},
};
// TODO(armansito|xow): Add tests for BR/EDR and dual mode bond data.
fn new_le_bond_data(id: &PeerId, address: &Address, name: &str, has_ltk: bool) -> BondingData {
BondingData {
identifier: id.to_string(),
local_address: "AA:BB:CC:DD:EE:FF".to_string(),
name: Some(name.to_string()),
le: Some(Box::new(LeData {
address: address.to_string(),
address_type: match address {
Address::Public(_) => AddressType::LePublic,
Address::Random(_) => AddressType::LeRandom,
},
connection_parameters: None,
services: vec![],
ltk: if has_ltk {
Some(Box::new(Ltk {
key: RemoteKey {
security_properties: SecurityProperties {
authenticated: true,
secure_connections: false,
encryption_key_size: 16,
},
value: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
},
key_size: 16,
ediv: 1,
rand: 2,
}))
} else {
None
},
irk: None,
csrk: None,
})),
bredr: None,
}
}
async fn add_bonds(
state: &HostDriverHarness,
mut bonds: Vec<BondingData>,
) -> Result<Status, Error> {
let fut = state.aux().proxy().add_bonded_devices(&mut bonds.iter_mut()).err_into();
fut.await
}
const TEST_ID1: PeerId = PeerId(0x1234);
const TEST_ID2: PeerId = PeerId(0x5678);
const TEST_ADDR1: Address = Address::Public([6, 5, 4, 3, 2, 1]);
const TEST_ADDR2: Address = Address::Public([1, 2, 3, 4, 5, 6]);
const TEST_NAME1: &str = "Name1";
const TEST_NAME2: &str = "Name2";
async fn test_add_no_bonds_succeeds(harness: HostDriverHarness) -> Result<(), Error> {
let status = add_bonds(&harness, vec![]).await?;
expect_true!(status.error.is_none())
}
// Tests initializing bonded LE devices.
async fn test_add_bonded_devices_success(harness: HostDriverHarness) -> Result<(), Error> {
// Peers should be initially empty.
expect_eq!(0, harness.state().peers().len())?;
let bond_data1 = new_le_bond_data(&TEST_ID1, &TEST_ADDR1, TEST_NAME1, true /* has LTK */);
let bond_data2 = new_le_bond_data(&TEST_ID2, &TEST_ADDR2, TEST_NAME2, true /* has LTK */);
let status = add_bonds(&harness, vec![bond_data1, bond_data2]).await?;
expect_true!(status.error.is_none())?;
// We should receive notifications for the newly added devices.
let expected1 = expectation::peer::address(TEST_ADDR1)
.and(expectation::peer::technology(fidl_fuchsia_bluetooth_sys::TechnologyType::LowEnergy))
.and(expectation::peer::name(TEST_NAME1))
.and(expectation::peer::bonded(true));
let expected2 = expectation::peer::address(TEST_ADDR2)
.and(expectation::peer::technology(fidl_fuchsia_bluetooth_sys::TechnologyType::LowEnergy))
.and(expectation::peer::name(TEST_NAME2))
.and(expectation::peer::bonded(true));
expect_peer(&harness, expected1).await?;
expect_peer(&harness, expected2).await?;
Ok(())
}
async fn test_add_bonded_devices_no_ltk_fails(harness: HostDriverHarness) -> Result<(), Error> {
// Peers should be initially empty.
expect_eq!(0, harness.state().peers().len())?;
// Inserting a bonded device without a LTK should fail.
let bond_data = new_le_bond_data(&TEST_ID1, &TEST_ADDR1, TEST_NAME1, false /* no LTK */);
let status = add_bonds(&harness, vec![bond_data]).await?;
expect_true!(status.error.is_some())?;
expect_eq!(0, harness.state().peers().len())?;
Ok(())
}
async fn test_add_bonded_devices_duplicate_entry(harness: HostDriverHarness) -> Result<(), Error> {
// Peers should be initially empty.
expect_eq!(0, harness.state().peers().len())?;
// Initialize one entry.
let bond_data = new_le_bond_data(&TEST_ID1, &TEST_ADDR1, TEST_NAME1, true /* with LTK */);
let status = add_bonds(&harness, vec![bond_data]).await?;
expect_true!(status.error.is_none())?;
// We should receive a notification for the newly added device.
let expected = expectation::peer::address(TEST_ADDR1)
.and(expectation::peer::technology(fidl_fuchsia_bluetooth_sys::TechnologyType::LowEnergy))
.and(expectation::peer::bonded(true));
expect_peer(&harness, expected.clone()).await?;
// Adding an entry with the existing id should fail.
let bond_data = new_le_bond_data(&TEST_ID1, &TEST_ADDR2, TEST_NAME2, true /* with LTK */);
let status = add_bonds(&harness, vec![bond_data]).await?;
expect_true!(status.error.is_some())?;
// Adding an entry with a different ID but existing address should fail.
let bond_data = new_le_bond_data(&TEST_ID2, &TEST_ADDR1, TEST_NAME1, true /* with LTK */);
let status = add_bonds(&harness, vec![bond_data]).await?;
expect_true!(status.error.is_some())?;
Ok(())
}
// Tests that adding a list of bonding data with malformed content succeeds for the valid entries
// but reports an error.
async fn test_add_bonded_devices_invalid_entry(harness: HostDriverHarness) -> Result<(), Error> {
// Peers should be initially empty.
expect_eq!(0, harness.state().peers().len())?;
// Add one entry with no LTK (invalid) and one with (valid). This should create an entry for the
// valid device but report an error for the invalid entry.
let no_ltk = new_le_bond_data(&TEST_ID1, &TEST_ADDR1, TEST_NAME1, false);
let with_ltk = new_le_bond_data(&TEST_ID2, &TEST_ADDR2, TEST_NAME2, true);
let status = add_bonds(&harness, vec![no_ltk, with_ltk]).await?;
expect_true!(status.error.is_some())?;
let expected = expectation::peer::address(TEST_ADDR2)
.and(expectation::peer::technology(fidl_fuchsia_bluetooth_sys::TechnologyType::LowEnergy))
.and(expectation::peer::bonded(true));
expect_peer(&harness, expected.clone()).await?;
Ok(())
}
/// Run all test cases.
pub fn run_all() -> Result<(), Error> {
run_suite!(
"bt-host driver bonding",
[
test_add_no_bonds_succeeds,
test_add_bonded_devices_success,
test_add_bonded_devices_no_ltk_fails,
test_add_bonded_devices_duplicate_entry,
test_add_bonded_devices_invalid_entry
]
)
}