blob: 03840ff4f861c80f9058f8758fb66b9f81ed2810 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bluetooth/newblued/newblue.h"
#include <memory>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <gtest/gtest.h>
#include "bluetooth/newblued/mock_libnewblue.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::ElementsAre;
using ::testing::Pair;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::UnorderedElementsAre;
namespace bluetooth {
namespace {
constexpr uniq_t kDiscoveryHandle = 11;
// A random handle value.
constexpr uniq_t kPairStateChangeHandle = 3;
constexpr uniq_t kPasskeyDisplayObserverHandle = 4;
} // namespace
class TestPairingAgent : public PairingAgent {
public:
void DisplayPasskey(const std::string& device_address,
uint32_t passkey) override {
displayed_passkeys.push_back({device_address, passkey});
}
std::vector<std::pair<std::string, uint32_t>> displayed_passkeys;
};
class NewblueTest : public ::testing::Test {
public:
// A dummy struct that hosts the device information from discovery callback.
struct MockDevice {
std::string address;
std::string name;
int16_t rssi;
uint32_t eir_class;
bool paired;
uint16_t appearance;
};
void SetUp() override {
auto libnewblue = std::make_unique<MockLibNewblue>();
libnewblue_ = libnewblue.get();
newblue_ = std::make_unique<Newblue>(std::move(libnewblue));
}
bool StubHciUp(const uint8_t* address,
hciReadyForUpCbk callback,
void* callback_data) {
callback(callback_data);
return true;
}
void OnReadyForUp() { is_ready_for_up_ = true; }
void OnDeviceDiscovered(const Device& device) {
discovered_devices_.push_back(
{device.address, device.name.value(), device.rssi.value(),
device.eir_class.value(), device.paired.value(),
device.appearance.value()});
}
void OnPairStateChanged(const Device& device,
PairState pair_state,
const std::string& dbus_error) {
for (auto& dev : discovered_devices_) {
if (dev.address == device.address)
dev.paired = device.paired.value();
}
}
void ExpectBringUp() {
newblue_->Init();
EXPECT_CALL(*libnewblue_, HciIsUp()).WillOnce(Return(false));
EXPECT_FALSE(newblue_->BringUp());
EXPECT_CALL(*libnewblue_, HciIsUp()).WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, L2cInit()).WillOnce(Return(0));
EXPECT_CALL(*libnewblue_, AttInit()).WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, GattProfileInit()).WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, GattBuiltinInit()).WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, SmInit()).WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, SmRegisterPairStateObserver(_, _))
.WillOnce(DoAll(SaveArg<0>(&pair_state_changed_callback_data_),
SaveArg<1>(&pair_state_changed_callback_),
Return(kPairStateChangeHandle)));
EXPECT_CALL(*libnewblue_, SmRegisterPasskeyDisplayObserver(_, _))
.WillOnce(DoAll(SaveArg<0>(&passkey_display_callback_data_),
SaveArg<1>(&passkey_display_callback_),
Return(kPasskeyDisplayObserverHandle)));
EXPECT_TRUE(newblue_->BringUp());
}
protected:
base::MessageLoop message_loop_;
bool is_ready_for_up_ = false;
std::unique_ptr<Newblue> newblue_;
MockLibNewblue* libnewblue_;
std::vector<MockDevice> discovered_devices_;
smPairStateChangeCbk pair_state_changed_callback_;
void* pair_state_changed_callback_data_ = nullptr;
smPasskeyDisplayCbk passkey_display_callback_;
void* passkey_display_callback_data_ = nullptr;
};
TEST_F(NewblueTest, ListenReadyForUp) {
newblue_->Init();
hciReadyForUpCbk up_callback;
EXPECT_CALL(*libnewblue_, HciUp(_, _, _))
.WillOnce(DoAll(SaveArg<1>(&up_callback),
Invoke(this, &NewblueTest::StubHciUp)));
bool success = newblue_->ListenReadyForUp(
base::Bind(&NewblueTest::OnReadyForUp, base::Unretained(this)));
EXPECT_TRUE(success);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(is_ready_for_up_);
// If libnewblue says the stack is ready for up again, ignore that.
// We shouldn't bring up the stack more than once.
is_ready_for_up_ = false;
up_callback(newblue_.get());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(is_ready_for_up_);
}
TEST_F(NewblueTest, ListenReadyForUpFailed) {
newblue_->Init();
EXPECT_CALL(*libnewblue_, HciUp(_, _, _)).WillOnce(Return(false));
bool success = newblue_->ListenReadyForUp(
base::Bind(&NewblueTest::OnReadyForUp, base::Unretained(this)));
EXPECT_FALSE(success);
}
TEST_F(NewblueTest, BringUp) {
ExpectBringUp();
}
TEST_F(NewblueTest, StartDiscovery) {
ExpectBringUp();
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, true, false))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kDiscoveryHandle)));
newblue_->StartDiscovery(
base::Bind(&NewblueTest::OnDeviceDiscovered, base::Unretained(this)));
// 2 devices discovered.
struct bt_addr addr1 = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
uint8_t eir1[] = {
6, static_cast<uint8_t>(EirType::NAME_SHORT), 'a', 'l', 'i', 'c', 'e'};
inquiry_response_callback(inquiry_response_callback_data, &addr1, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir1, arraysize(eir1));
struct bt_addr addr2 = {.type = BT_ADDR_TYPE_LE_PUBLIC,
.addr = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07}};
uint8_t eir2[] = {
5, static_cast<uint8_t>(EirType::NAME_SHORT), 'b', 'o', 'b', '\0'};
inquiry_response_callback(inquiry_response_callback_data, &addr2, -102,
HCI_ADV_TYPE_ADV_IND, &eir2, arraysize(eir2));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ("bob", discovered_devices_[1].name);
EXPECT_EQ("07:06:05:04:03:02", discovered_devices_[1].address);
EXPECT_EQ(-102, discovered_devices_[1].rssi);
// Scan response for device 1.
uint8_t eir3[] = {4, static_cast<uint8_t>(EirType::CLASS_OF_DEV), 0x21, 0x22,
0x23};
inquiry_response_callback(inquiry_response_callback_data, &addr1, -103,
HCI_ADV_TYPE_SCAN_RSP, &eir3, arraysize(eir3));
base::RunLoop().RunUntilIdle();
// The third discovery event should be an update to the first device, not a
// new device.
EXPECT_EQ(3, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[2].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[2].address);
EXPECT_EQ(-103, discovered_devices_[2].rssi);
EXPECT_EQ(0x232221, discovered_devices_[2].eir_class);
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kDiscoveryHandle))
.WillOnce(Return(true));
newblue_->StopDiscovery();
// Any inquiry response after StopDiscovery should be ignored.
inquiry_response_callback(inquiry_response_callback_data, &addr1, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir1, arraysize(eir1));
base::RunLoop().RunUntilIdle();
// Check that discovered_devices_ is still the same.
EXPECT_EQ(3, discovered_devices_.size());
}
TEST_F(NewblueTest, UpdateEirNormal) {
Device device;
uint8_t eir[] = {
// Flag
3, static_cast<uint8_t>(EirType::FLAGS), 0xAA, 0xBB,
// UUID16_COMPLETE - Battery Service
3, static_cast<uint8_t>(EirType::UUID16_COMPLETE), 0x0F, 0x18,
// UUID32_INCOMPLETE - Blood Pressure
5, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x10, 0x18, 0x00,
0x00,
// UUID128_COMPLETE
17, static_cast<uint8_t>(EirType::UUID128_COMPLETE), 0x0F, 0x0E, 0x0D,
0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0x00,
// Name
4, static_cast<uint8_t>(EirType::NAME_SHORT), 'f', 'o', 'o',
// TX Power
2, static_cast<uint8_t>(EirType::TX_POWER), 0xC7,
// Class
4, static_cast<uint8_t>(EirType::CLASS_OF_DEV), 0x01, 0x02, 0x03,
// Service data associated with 16-bit Battery Service UUID
5, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18, 0x22, 0x11,
// Service data associate with 32-bit Bond Management Service UUID
7, static_cast<uint8_t>(EirType::SVC_DATA32), 0x1E, 0x18, 0x00, 0x00,
0x44, 0x33,
// Appearance
3, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0x01, 0x02,
// Manufacturer data
5, static_cast<uint8_t>(EirType::MANUFACTURER_DATA), 0x0E, 0x00, 0x55,
0x66};
Uuid battery_service_uuid16(std::vector<uint8_t>({0x18, 0x0F}));
Uuid blood_pressure_uuid32(std::vector<uint8_t>({0x00, 0x00, 0x18, 0x10}));
Uuid bond_management_service_uuid32(
std::vector<uint8_t>({0x00, 0x00, 0x18, 0x1E}));
Uuid uuid128(
std::vector<uint8_t>({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}));
Newblue::UpdateEir(&device, std::vector<uint8_t>(eir, eir + arraysize(eir)));
EXPECT_EQ(std::vector<uint8_t>({0xAA}), device.flags.value());
EXPECT_THAT(device.service_uuids.value(),
UnorderedElementsAre(battery_service_uuid16,
blood_pressure_uuid32, uuid128));
EXPECT_EQ("foo", device.name.value());
EXPECT_EQ(-57, device.tx_power.value());
EXPECT_EQ(0x00030201, device.eir_class.value());
EXPECT_THAT(device.service_data.value(),
UnorderedElementsAre(Pair(battery_service_uuid16,
std::vector<uint8_t>({0x11, 0x22})),
Pair(bond_management_service_uuid32,
std::vector<uint8_t>({0x33, 0x44}))));
EXPECT_EQ(0x0201, device.appearance.value());
EXPECT_THAT(
device.manufacturer.value(),
UnorderedElementsAre(Pair(0x000E, std::vector<uint8_t>({0x55, 0x66}))));
uint8_t eir2[] = {
// Flag with zero octet
1, static_cast<uint8_t>(EirType::FLAGS),
// UUID32_INCOMPLETE - Bond Management Service
5, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x1E, 0x18, 0x00,
0x00,
// Service data associate with 32-bit Bond Management Service UUID
7, static_cast<uint8_t>(EirType::SVC_DATA32), 0x1E, 0x18, 0x00, 0x00,
0x66, 0x55};
Newblue::UpdateEir(&device,
std::vector<uint8_t>(eir2, eir2 + arraysize(eir2)));
EXPECT_FALSE(device.flags.value().empty());
EXPECT_THAT(device.service_uuids.value(),
UnorderedElementsAre(bond_management_service_uuid32));
EXPECT_EQ("foo", device.name.value());
EXPECT_EQ(-57, device.tx_power.value());
EXPECT_EQ(0x00030201, device.eir_class.value());
EXPECT_THAT(device.service_data.value(),
UnorderedElementsAre(Pair(bond_management_service_uuid32,
std::vector<uint8_t>({0x55, 0x66}))));
EXPECT_EQ(0x0201, device.appearance.value());
EXPECT_THAT(
device.manufacturer.value(),
UnorderedElementsAre(Pair(0x000E, std::vector<uint8_t>({0x55, 0x66}))));
}
TEST_F(NewblueTest, UpdateEirAbnormal) {
Device device;
uint8_t eir[] = {
// Even if there are more than one instance of a UUID size of either
// COMPLETE or INCOMPLETE type, the later one will still be honored
3, static_cast<uint8_t>(EirType::UUID16_COMPLETE), 0x0F, 0x18, //
3, static_cast<uint8_t>(EirType::UUID16_INCOMPLETE), 0x10, 0x18,
// Invalid UUID will be dropped.
2, static_cast<uint8_t>(EirType::UUID32_INCOMPLETE), 0x10,
// Contains non-ascii character
5, static_cast<uint8_t>(EirType::NAME_SHORT), 0x80, 0x81, 'a', '\0',
// TX Power with more than one octet will be dropped
3, static_cast<uint8_t>(EirType::TX_POWER), 0xC7, 0x00,
// Class with a wrong field length (2, should be 3)
3, static_cast<uint8_t>(EirType::CLASS_OF_DEV), 0x01, 0x02,
// Service data with an invalid service UUID will be dropped
3, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18,
// Service data with zero length associated with 16-bit Battery Service
// will be dropped
3, static_cast<uint8_t>(EirType::SVC_DATA16), 0x0F, 0x18,
// Wrong field length (4, should be 3)
4, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0x01, 0x02, 0x03};
Uuid battery_service_uuid16(std::vector<uint8_t>({0x18, 0x0F}));
Uuid blood_pressure_uuid16(std::vector<uint8_t>({0x18, 0x10}));
Newblue::UpdateEir(&device, std::vector<uint8_t>(eir, eir + arraysize(eir)));
// Non-ascii characters are replaced with spaces.
EXPECT_FALSE(device.flags.value().empty());
EXPECT_THAT(
device.service_uuids.value(),
UnorderedElementsAre(battery_service_uuid16, blood_pressure_uuid16));
EXPECT_EQ(" a", device.name.value());
EXPECT_EQ(-128, device.tx_power.value());
EXPECT_EQ(0x1F00, device.eir_class.value());
EXPECT_TRUE(device.service_data.value().empty());
EXPECT_EQ(0x0000, device.appearance.value());
EXPECT_THAT(device.manufacturer.value(),
UnorderedElementsAre(Pair(0xFFFF, std::vector<uint8_t>())));
}
TEST_F(NewblueTest, PairStateChangedToFailed) {
ExpectBringUp();
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, true, false))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kDiscoveryHandle)));
newblue_->StartDiscovery(
base::Bind(&NewblueTest::OnDeviceDiscovered, base::Unretained(this)));
// 1 device discovered.
struct bt_addr addr1 = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
uint8_t eir1[] = {
6, static_cast<uint8_t>(EirType::NAME_SHORT), 'a', 'l', 'i', 'c', 'e'};
inquiry_response_callback(inquiry_response_callback_data, &addr1, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir1, arraysize(eir1));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
// Register as a pairing state observer.
UniqueId pair_observer_handle = newblue_->RegisterAsPairObserver(
base::Bind(&NewblueTest::OnPairStateChanged, base::Unretained(this)));
EXPECT_NE(kInvalidUniqueId, pair_observer_handle);
// Pairing started.
struct smPairStateChange state_change = {.pairState = SM_PAIR_STATE_START,
.pairErr = SM_PAIR_ERR_NONE,
.peerAddr = addr1};
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
// Pairing failed with SM_PAIR_ERR_L2C_CONN error.
state_change.pairState = SM_PAIR_STATE_FAILED;
state_change.pairErr = SM_PAIR_ERR_L2C_CONN;
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
}
TEST_F(NewblueTest, PairStateChangedToPairedAndForgotten) {
ExpectBringUp();
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, true, false))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kDiscoveryHandle)));
newblue_->StartDiscovery(
base::Bind(&NewblueTest::OnDeviceDiscovered, base::Unretained(this)));
// 1 device discovered.
struct bt_addr addr1 = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
uint8_t eir1[] = {
6, static_cast<uint8_t>(EirType::NAME_SHORT), 'a', 'l', 'i', 'c', 'e'};
inquiry_response_callback(inquiry_response_callback_data, &addr1, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir1, arraysize(eir1));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
// Register as a pairing state observer.
UniqueId pair_observer_handle = newblue_->RegisterAsPairObserver(
base::Bind(&NewblueTest::OnPairStateChanged, base::Unretained(this)));
EXPECT_NE(kInvalidUniqueId, pair_observer_handle);
// Pairing started.
struct smPairStateChange state_change = {.pairState = SM_PAIR_STATE_START,
.pairErr = SM_PAIR_ERR_NONE,
.peerAddr = addr1};
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
// Pairing finished successfully.
state_change.pairState = SM_PAIR_STATE_PAIRED;
state_change.pairErr = SM_PAIR_ERR_NONE;
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(true, discovered_devices_[0].paired);
// Pairing forgotten.
state_change.pairState = SM_PAIR_STATE_NOT_PAIRED;
state_change.pairErr = SM_PAIR_ERR_NONE;
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
// Unregister as a pairing state observer.
newblue_->UnregisterAsPairObserver(pair_observer_handle);
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
// Pairing finished successfully.
state_change.pairState = SM_PAIR_STATE_PAIRED;
state_change.pairErr = SM_PAIR_ERR_NONE;
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("alice", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
// There should be no update on the pairing state.
EXPECT_EQ(false, discovered_devices_[0].paired);
}
TEST_F(NewblueTest, Pair) {
ExpectBringUp();
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, true, false))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kDiscoveryHandle)));
newblue_->StartDiscovery(
base::Bind(&NewblueTest::OnDeviceDiscovered, base::Unretained(this)));
// 1 device discovered.
struct bt_addr addr = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
std::string device_addr("06:05:04:03:02:01");
uint8_t eir[] = {
// Flag
3, static_cast<uint8_t>(EirType::FLAGS), 0xAA, 0xBB,
// Name
6, static_cast<uint8_t>(EirType::NAME_SHORT), 'm', 'o', 'u', 's', 'e',
// Appearance
3, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0xc2, 0x03};
inquiry_response_callback(inquiry_response_callback_data, &addr, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir, arraysize(eir));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("mouse", discovered_devices_[0].name);
EXPECT_EQ(device_addr, discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
EXPECT_EQ(0x03c2, discovered_devices_[0].appearance);
EXPECT_CALL(*libnewblue_, SmPair(_, _)).WillOnce(Return());
EXPECT_TRUE(newblue_->Pair(device_addr));
base::RunLoop().RunUntilIdle();
}
TEST_F(NewblueTest, PairWithUnknownDevice) {
ExpectBringUp();
std::string device_addr("06:05:04:03:02:01");
EXPECT_FALSE(newblue_->Pair(device_addr));
}
TEST_F(NewblueTest, CancelPairing) {
ExpectBringUp();
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, true, false))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kDiscoveryHandle)));
newblue_->StartDiscovery(
base::Bind(&NewblueTest::OnDeviceDiscovered, base::Unretained(this)));
// 1 device discovered.
struct bt_addr addr = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
std::string device_addr("06:05:04:03:02:01");
uint8_t eir[] = {
// Flag
3, static_cast<uint8_t>(EirType::FLAGS), 0xAA, 0xBB,
// Name
6, static_cast<uint8_t>(EirType::NAME_SHORT), 'm', 'o', 'u', 's', 'e',
// Appearance
3, static_cast<uint8_t>(EirType::GAP_APPEARANCE), 0xc2, 0x03};
inquiry_response_callback(inquiry_response_callback_data, &addr, -101,
HCI_ADV_TYPE_SCAN_RSP, &eir, arraysize(eir));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("mouse", discovered_devices_[0].name);
EXPECT_EQ(device_addr, discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
EXPECT_EQ(0x03c2, discovered_devices_[0].appearance);
// Register as a pairing state observer.
UniqueId pair_observer_handle = newblue_->RegisterAsPairObserver(
base::Bind(&NewblueTest::OnPairStateChanged, base::Unretained(this)));
EXPECT_NE(kInvalidUniqueId, pair_observer_handle);
EXPECT_CALL(*libnewblue_, SmPair(_, _)).WillOnce(Return());
EXPECT_TRUE(newblue_->Pair(device_addr));
base::RunLoop().RunUntilIdle();
// Pairing started.
struct smPairStateChange state_change = {.pairState = SM_PAIR_STATE_START,
.pairErr = SM_PAIR_ERR_NONE,
.peerAddr = addr};
pair_state_changed_callback_(pair_state_changed_callback_data_, &state_change,
kPairStateChangeHandle);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, discovered_devices_.size());
EXPECT_EQ("mouse", discovered_devices_[0].name);
EXPECT_EQ("06:05:04:03:02:01", discovered_devices_[0].address);
EXPECT_EQ(-101, discovered_devices_[0].rssi);
EXPECT_EQ(false, discovered_devices_[0].paired);
EXPECT_EQ(0x03c2, discovered_devices_[0].appearance);
// Cancel pairing.
EXPECT_CALL(*libnewblue_, SmUnpair(_)).WillOnce(Return());
EXPECT_TRUE(newblue_->CancelPair(device_addr));
base::RunLoop().RunUntilIdle();
}
TEST_F(NewblueTest, CancelPairingWithUnknownDevice) {
ExpectBringUp();
std::string device_addr("06:05:04:03:02:01");
EXPECT_FALSE(newblue_->CancelPair(device_addr));
}
TEST_F(NewblueTest, PasskeyDisplayObserver) {
ExpectBringUp();
TestPairingAgent pairing_agent;
newblue_->RegisterPairingAgent(&pairing_agent);
struct bt_addr peer_addr = {.type = BT_ADDR_TYPE_LE_RANDOM,
.addr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
struct smPasskeyDisplay passkey_display = {
.valid = true, .passkey = 123456, .peerAddr = peer_addr};
passkey_display_callback_(passkey_display_callback_data_, &passkey_display,
kPasskeyDisplayObserverHandle);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(pairing_agent.displayed_passkeys,
ElementsAre(Pair("06:05:04:03:02:01", 123456)));
}
} // namespace bluetooth