blob: 6c65233b1b89efc94ee636e736124d9349e2150f [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_daemon.h"
#include <cstdlib>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/memory/ref_counted.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <base/values.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_exported_object.h>
#include <dbus/mock_object_manager.h>
#include <dbus/mock_object_proxy.h>
#include <dbus/object_manager.h>
#include <dbus/values_util.h>
#include <gtest/gtest.h>
#include "bluetooth/newblued/mock_libnewblue.h"
#include "bluetooth/newblued/util.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
namespace bluetooth {
namespace {
constexpr char kTestSender[] = ":1.1";
constexpr char kTestSender2[] = ":1.2";
constexpr int kTestSerial = 10;
constexpr char kTestDeviceAddress[] = "06:05:04:03:02:01";
constexpr char kTestDeviceAddress2[] = "06:05:04:03:02:02";
constexpr char kLatestAddress[] = "16:15:14:13:12:11";
constexpr char kTestDeviceObjectPath[] =
"/org/bluez/hci0/dev_06_05_04_03_02_01";
constexpr char kTestDeviceObjectPath2[] =
"/org/bluez/hci0/dev_06_05_04_03_02_02";
constexpr char kUnknownDeviceObjectPath[] =
"/org/bluez/hci0/dev_FF_FF_FF_FF_FF_FF";
constexpr uniq_t kTestDiscoveryId = 7;
constexpr gatt_client_conn_t kTestGattClientConnectionId = 3;
const std::map<std::string, brillo::VariantDictionary> filters = {
{"clear", {}},
{"classic_loose",
{
{"Transport", std::string{"bredr"}},
{"RSSI", int16_t{-120}},
{"Pathloss", uint16_t{120}},
}},
{"tight",
{{"Transport", std::string{"auto"}},
{"RSSI", int16_t{-80}},
{"Pathloss", uint16_t{20}},
{"UUIDs",
std::vector<std::string>{"0000181e-0000-1000-8000-00805f9b34fb"}}}},
{"loose",
{
{"Transport", std::string{"auto"}},
{"RSSI", int16_t{-120}},
{"Pathloss", uint16_t{120}},
}},
{"looser_rssi",
{{"Transport", std::string{"le"}},
{"RSSI", int16_t{-100}},
{"Pathloss", uint16_t{20}},
{"UUIDs",
std::vector<std::string>{"0000181e-0000-1000-8000-00805f9b34fb"}}}},
{"uuid",
{{"Transport", std::string{"le"}},
{"RSSI", int16_t{-100}},
{"Pathloss", uint16_t{20}},
{"UUIDs",
std::vector<std::string>{"0000181f-0000-1000-8000-00805f9b34fb"}}}}};
constexpr 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), 0xFB, 0x34, 0x9B, 0x5F,
0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x1E, 0x18, 0x00, 0x00,
// Name
4, static_cast<uint8_t>(EirType::NAME_SHORT), 'f', 'o', 'o',
// TX Power
2, static_cast<uint8_t>(EirType::TX_POWER), 0x0A,
// 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};
void SaveResponse(std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
}
} // namespace
class NewblueDaemonTest : public ::testing::Test {
public:
using MethodHandlerMap =
std::map<std::string, dbus::ExportedObject::MethodCallCallback*>;
void SetUp() override {
bus_ = new dbus::MockBus(dbus::Bus::Options());
EXPECT_CALL(*bus_, GetDBusTaskRunner())
.WillRepeatedly(Return(message_loop_.task_runner().get()));
EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
EXPECT_CALL(*bus_, Connect()).WillRepeatedly(Return(true));
EXPECT_CALL(*bus_, SetUpAsyncOperations()).WillRepeatedly(Return(true));
EXPECT_CALL(*bus_, SendWithReplyAndBlock(_, _, _)).Times(AnyNumber());
EXPECT_CALL(*bus_, AddFilterFunction(_, _)).Times(AnyNumber());
EXPECT_CALL(*bus_, RemoveFilterFunction(_, _)).Times(AnyNumber());
EXPECT_CALL(*bus_, AddMatch(_, _)).Times(AnyNumber());
EXPECT_CALL(*bus_, RemoveMatch(_, _)).Times(AnyNumber());
auto libnewblue = std::make_unique<MockLibNewblue>();
libnewblue_ = libnewblue.get();
auto newblue = std::make_unique<Newblue>(std::move(libnewblue));
newblue_daemon_ = std::make_unique<NewblueDaemon>(std::move(newblue),
false /* is_idle_mode */);
SetupBluezObjectProxy();
SetupBluezObjectManager();
// Force MessageLoop to run all pending tasks as an effect of instantiating
// MockObjectManager. This is needed to avoid memory leak as pending tasks
// hold pointers.
base::RunLoop().RunUntilIdle();
}
protected:
dbus::ExportedObject::MethodCallCallback* GetMethodHandler(
MethodHandlerMap method_handlers, const std::string& method_name) {
return base::ContainsKey(method_handlers, method_name)
? method_handlers[method_name]
: &dummy_method_handler_;
}
// Expects that the standard methods on org.freedesktop.DBus.Properties
// interface are exported.
void ExpectPropertiesMethodsExportedAsync(
scoped_refptr<dbus::MockExportedObject> exported_object) {
EXPECT_CALL(*exported_object, ExportMethod(dbus::kPropertiesInterface,
dbus::kPropertiesGet, _, _))
.Times(1);
EXPECT_CALL(*exported_object, ExportMethod(dbus::kPropertiesInterface,
dbus::kPropertiesSet, _, _))
.Times(1);
EXPECT_CALL(*exported_object, ExportMethod(dbus::kPropertiesInterface,
dbus::kPropertiesGetAll, _, _))
.Times(1);
}
// Expects that the standard methods on org.freedesktop.DBus.Properties
// interface are exported.
void ExpectPropertiesMethodsExported(
scoped_refptr<dbus::MockExportedObject> exported_object,
MethodHandlerMap method_handlers) {
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(dbus::kPropertiesInterface,
dbus::kPropertiesGet, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(method_handlers, dbus::kPropertiesGet)),
Return(true)));
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(dbus::kPropertiesInterface,
dbus::kPropertiesSet, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(method_handlers, dbus::kPropertiesSet)),
Return(true)));
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(dbus::kPropertiesInterface,
dbus::kPropertiesGetAll, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(method_handlers,
dbus::kPropertiesGetAll)),
Return(true)));
}
// Expects that the methods on org.bluez.Device1 interface are exported.
void ExpectDeviceMethodsExported(
scoped_refptr<dbus::MockExportedObject> exported_object,
MethodHandlerMap method_handlers) {
EXPECT_CALL(
*exported_object,
ExportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kPair, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(method_handlers,
bluetooth_device::kPair)),
Return(true)));
EXPECT_CALL(
*exported_object,
ExportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kCancelPairing, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
method_handlers, bluetooth_device::kCancelPairing)),
Return(true)));
EXPECT_CALL(
*exported_object,
ExportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kConnect, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
method_handlers, bluetooth_device::kConnect)),
Return(true)));
EXPECT_CALL(
*exported_object,
ExportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kDisconnect, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
method_handlers, bluetooth_device::kDisconnect)),
Return(true)));
EXPECT_CALL(
*exported_object,
ExportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kExecuteWrite, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
method_handlers, bluetooth_device::kExecuteWrite)),
Return(true)));
}
// Expects that the methods on org.bluez.Device1 interface are unexported.
void ExpectDeviceMethodsUnexported(
scoped_refptr<dbus::MockExportedObject> exported_object) {
EXPECT_CALL(
*exported_object,
UnexportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kPair))
.WillOnce(Return(true));
EXPECT_CALL(
*exported_object,
UnexportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kCancelPairing))
.WillOnce(Return(true));
EXPECT_CALL(
*exported_object,
UnexportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kConnect))
.WillOnce(Return(true));
EXPECT_CALL(
*exported_object,
UnexportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kDisconnect))
.WillOnce(Return(true));
EXPECT_CALL(
*exported_object,
UnexportMethodAndBlock(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kExecuteWrite))
.WillOnce(Return(true));
}
// Expects that the methods on org.bluez.AdvertisingManager1 interface are
// exported.
void ExpectAdvertisingManagerMethodsExported(
scoped_refptr<dbus::MockExportedObject> exported_object) {
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(
bluetooth_advertising_manager::
kBluetoothAdvertisingManagerInterface,
bluetooth_advertising_manager::kRegisterAdvertisement, _))
.WillOnce(Return(true));
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(
bluetooth_advertising_manager::
kBluetoothAdvertisingManagerInterface,
bluetooth_advertising_manager::kUnregisterAdvertisement, _))
.WillOnce(Return(true));
}
// Expects that the methods on org.bluez.AgentManager1 interface are
// exported.
void ExpectAgentManagerMethodsExported(
scoped_refptr<dbus::MockExportedObject> exported_object) {
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRegisterAgent, _))
.WillOnce(Return(true));
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kUnregisterAgent, _))
.WillOnce(Return(true));
EXPECT_CALL(*exported_object,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRequestDefaultAgent, _))
.WillOnce(Return(true));
}
scoped_refptr<dbus::MockExportedObject> AddOrGetMockExportedObject(
const dbus::ObjectPath& object_path) {
if (base::ContainsKey(mock_exported_objects_, object_path))
return mock_exported_objects_[object_path];
scoped_refptr<dbus::MockExportedObject> exported_object =
new dbus::MockExportedObject(bus_.get(), object_path);
mock_exported_objects_[object_path] = exported_object;
return exported_object;
}
void RemoveMockExportedObject(const dbus::ObjectPath& object_path) {
if (base::ContainsKey(mock_exported_objects_, object_path))
mock_exported_objects_.erase(object_path);
}
void ExpectDeviceObjectExported(const dbus::ObjectPath& device_object_path,
MethodHandlerMap method_handlers) {
scoped_refptr<dbus::MockExportedObject> exported_dev_object =
AddOrGetMockExportedObject(device_object_path);
ExpectDeviceMethodsExported(exported_dev_object, method_handlers);
ExpectPropertiesMethodsExported(exported_dev_object, method_handlers);
EXPECT_CALL(*bus_, GetExportedObject(device_object_path))
.WillOnce(Return(exported_dev_object.get()));
EXPECT_CALL(*exported_dev_object, SendSignal(_)).Times(AnyNumber());
}
void ExpectDeviceObjectUnexported(
const dbus::ObjectPath& device_object_path) {
scoped_refptr<dbus::MockExportedObject> exported_dev_object =
AddOrGetMockExportedObject(device_object_path);
ExpectDeviceMethodsUnexported(exported_dev_object);
EXPECT_CALL(*exported_dev_object, Unregister()).Times(1);
}
void ExpectDeviceObjectNotExported(
const dbus::ObjectPath& device_object_path) {
scoped_refptr<dbus::MockExportedObject> exported_dev_object =
AddOrGetMockExportedObject(device_object_path);
EXPECT_CALL(*bus_, GetExportedObject(device_object_path)).Times(0);
EXPECT_CALL(*exported_dev_object, SendSignal(_)).Times(0);
}
scoped_refptr<dbus::MockExportedObject> SetupExportedRootObject() {
dbus::ObjectPath root_path(
newblue_object_manager::kNewblueObjectManagerServicePath);
scoped_refptr<dbus::MockExportedObject> exported_root_object =
new dbus::MockExportedObject(bus_.get(), root_path);
EXPECT_CALL(*bus_, GetExportedObject(root_path))
.WillRepeatedly(Return(exported_root_object.get()));
EXPECT_CALL(*exported_root_object, SendSignal(_)).Times(AnyNumber());
return exported_root_object;
}
scoped_refptr<dbus::MockExportedObject> SetupExportedAgentManagerObject() {
dbus::ObjectPath agent_manager_path(
bluetooth_agent_manager::kBluetoothAgentManagerServicePath);
scoped_refptr<dbus::MockExportedObject> exported_agent_manager_object =
new dbus::MockExportedObject(bus_.get(), agent_manager_path);
EXPECT_CALL(*bus_, GetExportedObject(agent_manager_path))
.WillRepeatedly(Return(exported_agent_manager_object.get()));
return exported_agent_manager_object;
}
scoped_refptr<dbus::MockExportedObject> SetupExportedAdapterObject() {
dbus::ObjectPath adapter_object_path(kAdapterObjectPath);
scoped_refptr<dbus::MockExportedObject> exported_adapter_object =
new dbus::MockExportedObject(bus_.get(), adapter_object_path);
EXPECT_CALL(*bus_, GetExportedObject(adapter_object_path))
.WillRepeatedly(Return(exported_adapter_object.get()));
return exported_adapter_object;
}
void SetupBluezObjectProxy() {
dbus::ObjectPath bluez_object_path(
bluez_object_manager::kBluezObjectManagerServicePath);
bluez_object_proxy_ = new dbus::MockObjectProxy(
bus_.get(), bluez_object_manager::kBluezObjectManagerServiceName,
bluez_object_path);
EXPECT_CALL(*bus_, GetObjectProxy(
bluez_object_manager::kBluezObjectManagerServiceName,
bluez_object_path))
.WillRepeatedly(Return(bluez_object_proxy_.get()));
EXPECT_CALL(*bluez_object_proxy_, SetNameOwnerChangedCallback(_))
.Times(AnyNumber());
EXPECT_CALL(*bluez_object_proxy_, ConnectToSignal(_, _, _, _))
.Times(AnyNumber());
dbus::ObjectPath bluetooth_object_path(
bluez_object_manager::kBluezObjectManagerServicePath);
bluetooth_object_proxy_ = new dbus::MockObjectProxy(
bus_.get(),
bluetooth_object_manager::kBluetoothObjectManagerServiceName,
bluetooth_object_path);
EXPECT_CALL(
*bus_, GetObjectProxy(
bluetooth_object_manager::kBluetoothObjectManagerServiceName,
bluetooth_object_path))
.WillRepeatedly(Return(bluetooth_object_proxy_.get()));
}
void SetupBluezObjectManager() {
dbus::ObjectPath bluez_object_path(
bluez_object_manager::kBluezObjectManagerServicePath);
bluez_object_manager_ = new dbus::MockObjectManager(
bus_.get(), bluez_object_manager::kBluezObjectManagerServiceName,
bluez_object_path);
EXPECT_CALL(*bus_, GetObjectManager(
bluez_object_manager::kBluezObjectManagerServiceName,
bluez_object_path))
.WillRepeatedly(Return(bluez_object_manager_.get()));
dbus::ObjectPath bluetooth_object_path(
bluetooth_object_manager::kBluetoothObjectManagerServicePath);
bluetooth_object_manager_ = new dbus::MockObjectManager(
bus_.get(),
bluetooth_object_manager::kBluetoothObjectManagerServiceName,
bluetooth_object_path);
EXPECT_CALL(
*bus_, GetObjectManager(
bluetooth_object_manager::kBluetoothObjectManagerServiceName,
bluetooth_object_path))
.WillRepeatedly(Return(bluetooth_object_manager_.get()));
}
struct smKnownDevNode* CreateSmKnownDeviceNode(const std::string& address,
bool is_random_address,
bool is_paired,
std::string name) {
struct smKnownDevNode* node =
(struct smKnownDevNode*)calloc(1, sizeof(struct smKnownDevNode));
ConvertToBtAddr(is_random_address, address, &node->addr);
node->isPaired = is_paired;
node->name = strdup(name.c_str());
return node;
}
struct smKnownDevNode* StubGetKnownDevices() {
struct smKnownDevNode* node1 = CreateSmKnownDeviceNode(
"01:AA:BB:CC:DD:EE", /* is_random_address */ true,
/* is_paired */ true, "Test Device 1");
struct smKnownDevNode* node2 = CreateSmKnownDeviceNode(
"02:AA:BB:CC:DD:EE", /* is_random_address */ true,
/* is_paired */ false, "Test Device 2");
struct smKnownDevNode* node3 = CreateSmKnownDeviceNode(
"03:AA:BB:CC:DD:EE", /* is_random_address */ false,
/* is_paired */ true, "Test Device 3");
node1->next = node2;
node2->next = node3;
node3->next = nullptr;
return node1;
}
void ExpectTestInit(
scoped_refptr<dbus::MockExportedObject> exported_root_object) {
EXPECT_CALL(*bus_,
RequestOwnershipAndBlock(
newblue_object_manager::kNewblueObjectManagerServiceName,
dbus::Bus::REQUIRE_PRIMARY))
.WillOnce(Return(true));
// Standard methods on org.freedesktop.DBus.ObjectManager interface should
// be exported.
EXPECT_CALL(*exported_root_object,
ExportMethod(dbus::kObjectManagerInterface,
dbus::kObjectManagerGetManagedObjects, _, _))
.Times(1);
// Standard methods on org.freedesktop.DBus.Properties interface should be
// exported.
ExpectPropertiesMethodsExportedAsync(exported_root_object);
}
void TestInit(MethodHandlerMap adapter_method_handlers) {
exported_root_object_ = SetupExportedRootObject();
exported_agent_manager_object_ = SetupExportedAgentManagerObject();
exported_adapter_object_ = SetupExportedAdapterObject();
ExpectPropertiesMethodsExported(exported_adapter_object_,
adapter_method_handlers);
ExpectAdvertisingManagerMethodsExported(exported_adapter_object_);
ExpectPropertiesMethodsExported(exported_agent_manager_object_,
adapter_method_handlers);
ExpectAgentManagerMethodsExported(exported_agent_manager_object_);
ExpectTestInit(exported_root_object_);
EXPECT_CALL(*libnewblue_, HciUp(_, _, _)).WillOnce(Return(true));
EXPECT_TRUE(newblue_daemon_->Init(
bus_, nullptr /* no need to access the delegator */));
}
void TestDeinit() {
EXPECT_CALL(*exported_root_object_, Unregister()).Times(1);
EXPECT_CALL(*exported_adapter_object_, Unregister()).Times(1);
EXPECT_CALL(*exported_agent_manager_object_, Unregister()).Times(1);
// Expect that all the exported objects are unregistered.
for (const auto it : mock_exported_objects_) {
scoped_refptr<dbus::MockExportedObject> mock_exported_object = it.second;
EXPECT_CALL(*mock_exported_object, Unregister()).Times(1);
}
// Shutdown now to make sure ExportedObjectManagerWrapper is destructed
// first before the mocked objects.
newblue_daemon_->Shutdown();
}
// |with_saved_devices| controls whether there is paired devices saved in
// persist. Useful for some tests that want to start with a clean device list.
void TestAdapterBringUp(
scoped_refptr<dbus::MockExportedObject> exported_adapter_object,
MethodHandlerMap adapter_method_handlers,
bool with_saved_devices) {
// org.bluez.Adapter1 methods
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kSetDiscoveryFilter, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
adapter_method_handlers,
bluetooth_adapter::kSetDiscoveryFilter)),
Return(true)));
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStartDiscovery, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(adapter_method_handlers,
bluetooth_adapter::kStartDiscovery)),
Return(true)));
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(adapter_method_handlers,
bluetooth_adapter::kStopDiscovery)),
Return(true)));
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(adapter_method_handlers,
bluetooth_adapter::kRemoveDevice)),
Return(true)));
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kHandleSuspendImminent, _))
.WillOnce(DoAll(SaveArg<2>(GetMethodHandler(
adapter_method_handlers,
bluetooth_adapter::kHandleSuspendImminent)),
Return(true)));
EXPECT_CALL(
*exported_adapter_object,
ExportMethodAndBlock(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kHandleSuspendDone, _))
.WillOnce(DoAll(
SaveArg<2>(GetMethodHandler(adapter_method_handlers,
bluetooth_adapter::kHandleSuspendDone)),
Return(true)));
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_, SmRegisterPasskeyDisplayObserver(_, _))
.WillOnce(Return(true));
EXPECT_CALL(*libnewblue_, SmRegisterPairStateObserver(_, _))
.WillOnce(DoAll(SaveArg<0>(&pair_state_callback_data_),
SaveArg<1>(&pair_state_callback_), Return(true)));
EXPECT_CALL(*libnewblue_, BtleHidInit(_, _)).Times(1);
struct smKnownDevNode* known_devices = nullptr;
if (with_saved_devices) {
// At initialization, newblued should export the saved paired devices.
ExpectDeviceObjectExported(
dbus::ObjectPath("/org/bluez/hci0/dev_01_AA_BB_CC_DD_EE"), {});
ExpectDeviceObjectExported(
dbus::ObjectPath("/org/bluez/hci0/dev_03_AA_BB_CC_DD_EE"), {});
known_devices = StubGetKnownDevices();
}
EXPECT_CALL(*libnewblue_, SmGetKnownDevices())
.WillOnce(Return(known_devices));
EXPECT_CALL(*libnewblue_, SmKnownDevicesFree(known_devices))
.WillOnce(Invoke(&smKnownDevicesFree));
// Listens to BlueZ's Adapter1 interface for monitoring StackSyncQuitting.
EXPECT_CALL(
*bluez_object_manager_,
RegisterInterface(bluetooth_adapter::kBluetoothAdapterInterface, _))
.Times(1);
newblue_daemon_->OnHciReadyForUp();
}
void ConstructRemoveDeviceMethodCall(
dbus::MethodCall* remove_device_method_call,
const std::string device_object_path) {
remove_device_method_call->SetPath(dbus::ObjectPath(kAdapterObjectPath));
remove_device_method_call->SetSender(kTestSender);
remove_device_method_call->SetSerial(kTestSerial);
dbus::MessageWriter writer(remove_device_method_call);
writer.AppendObjectPath(dbus::ObjectPath(device_object_path));
}
void CallSetDiscoveryFilterMethod(
dbus::ExportedObject::MethodCallCallback set_discovery_filter_handler,
std::string sender,
std::string filter_type) {
// Initialization for Set Discovery Filter method.
dbus::MethodCall set_discovery_filter_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kSetDiscoveryFilter);
std::unique_ptr<dbus::Response> set_discovery_filter_response;
set_discovery_filter_method_call.SetPath(
dbus::ObjectPath(kAdapterObjectPath));
set_discovery_filter_method_call.SetSender(sender);
set_discovery_filter_method_call.SetSerial(kTestSerial);
dbus::MessageWriter writer(&set_discovery_filter_method_call);
brillo::dbus_utils::AppendValueToWriter(&writer,
filters.find(filter_type)->second);
set_discovery_filter_handler.Run(
&set_discovery_filter_method_call,
base::Bind(&SaveResponse, &set_discovery_filter_response));
}
// Tests org.bluez.Adapter1.StartDiscovery
void TestStartDiscovery(
dbus::ExportedObject::MethodCallCallback start_discovery_handler,
hciDeviceDiscoveredLeCbk* inquiry_response_callback,
void** inquiry_response_callback_data) {
// StartDiscovery by the first client, it should return D-Bus success and
// should trigger NewBlue StartDiscovery.
dbus::MethodCall start_discovery_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStartDiscovery);
start_discovery_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
start_discovery_method_call.SetSender(kTestSender);
start_discovery_method_call.SetSerial(kTestSerial);
std::unique_ptr<dbus::Response> start_discovery_response;
Newblue::DeviceDiscoveredCallback on_device_discovered;
EXPECT_CALL(*libnewblue_,
HciDiscoverLeStart(_, _, /* active */ true, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(inquiry_response_callback),
SaveArg<1>(inquiry_response_callback_data),
Return(kTestDiscoveryId)));
start_discovery_handler.Run(
&start_discovery_method_call,
base::Bind(&SaveResponse, &start_discovery_response));
EXPECT_EQ("", start_discovery_response->GetErrorName());
ASSERT_NE(nullptr, *inquiry_response_callback);
ASSERT_NE(nullptr, *inquiry_response_callback_data);
// StartDiscovery again by the same client, it should return D-Bus error and
// should not affect NewBlue discovery state.
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, _, _, _, _, _, _))
.Times(0);
start_discovery_handler.Run(
&start_discovery_method_call,
base::Bind(&SaveResponse, &start_discovery_response));
EXPECT_EQ(bluetooth_adapter::kErrorInProgress,
start_discovery_response->GetErrorName());
// StartDiscovery by a different client, it should return D-Bus success and
// should not affect NewBlue discovery state since it has already been
// started.
start_discovery_method_call.SetSender(kTestSender2);
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, _, _, _, _, _, _))
.Times(0);
start_discovery_handler.Run(
&start_discovery_method_call,
base::Bind(&SaveResponse, &start_discovery_response));
EXPECT_EQ("", start_discovery_response->GetErrorName());
}
void TestStopDiscovery(
dbus::ExportedObject::MethodCallCallback stop_discovery_handler) {
// StopDiscovery by the first client, it should return D-Bus success and
// should not affect NewBlue discovery state since there is still another
// client having discovery session.
dbus::MethodCall stop_discovery_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery);
stop_discovery_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
stop_discovery_method_call.SetSender(kTestSender);
stop_discovery_method_call.SetSerial(kTestSerial);
std::unique_ptr<dbus::Response> stop_discovery_response;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(_)).Times(0);
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
EXPECT_EQ("", stop_discovery_response->GetErrorName());
// StopDiscovery again by the same client, it should return D-Bus error, and
// should not affect the NewBlue discovery state.
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(_)).Times(0);
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
EXPECT_EQ(bluetooth_adapter::kErrorFailed,
stop_discovery_response->GetErrorName());
// StopDiscovery by the other client, it should return D-Bus success, and
// should trigger NewBlue's StopDiscovery since there is no more client
// having a discovery session.
stop_discovery_method_call.SetSender(kTestSender2);
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
EXPECT_EQ("", stop_discovery_response->GetErrorName());
}
std::unique_ptr<dbus::Response> ReadProperty(
const std::string& interface_name,
const std::string& property_name,
dbus::ExportedObject::MethodCallCallback get_property_handler,
const char* sender,
int serial) {
std::unique_ptr<dbus::Response> get_property_response;
dbus::MethodCall get_property_method_call(dbus::kPropertiesInterface,
dbus::kPropertiesGet);
get_property_method_call.SetSender(sender);
get_property_method_call.SetSerial(serial);
dbus::MessageWriter get_property_message_writer(&get_property_method_call);
get_property_message_writer.AppendString(interface_name);
get_property_message_writer.AppendString(property_name);
get_property_handler.Run(&get_property_method_call,
base::Bind(&SaveResponse, &get_property_response));
EXPECT_TRUE(get_property_response != nullptr);
return get_property_response;
}
// Tests org.bluez.Device1.Connect() and org.bluez.Device1.Disconnect()
void TestConnectDisconnect(
dbus::ExportedObject::MethodCallCallback connect_handler,
dbus::ExportedObject::MethodCallCallback disconnect_handler,
dbus::ExportedObject::MethodCallCallback get_property_handler,
const struct bt_addr* address) {
dbus::MethodCall connect_method_call(
bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kConnect);
connect_method_call.SetSender(kTestSender);
connect_method_call.SetSerial(kTestSerial);
// Unknown device path
std::unique_ptr<dbus::Response> failed_connect_response;
connect_method_call.SetPath(dbus::ObjectPath(kUnknownDeviceObjectPath));
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _)).Times(0);
connect_handler.Run(&connect_method_call,
base::Bind(&SaveResponse, &failed_connect_response));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(bluetooth_device::kErrorDoesNotExist,
failed_connect_response->GetErrorName());
// GattClientConnect() fails.
connect_method_call.SetPath(dbus::ObjectPath(kTestDeviceObjectPath));
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _)).WillOnce(Return(0));
connect_handler.Run(&connect_method_call,
base::Bind(&SaveResponse, &failed_connect_response));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(bluetooth_device::kErrorFailed,
failed_connect_response->GetErrorName());
// GattClientConnect() succeeds.
void* data;
struct bt_addr addr;
gattCliConnectResultCbk gatt_client_connect_callback;
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _))
.WillOnce(DoAll(SaveArg<0>(&data), SaveArgPointee<1>(&addr),
SaveArg<2>(&gatt_client_connect_callback),
Return(kTestGattClientConnectionId)));
std::unique_ptr<dbus::Response> success_connect_response;
connect_handler.Run(&connect_method_call,
base::Bind(&SaveResponse, &success_connect_response));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(success_connect_response.get());
EXPECT_EQ(ConvertBtAddrToString(addr), ConvertBtAddrToString(*address));
// Callback for a different connection id should be ignored.
gatt_client_connect_callback(data, kTestGattClientConnectionId + 10,
static_cast<uint8_t>(ConnectState::CONNECTED));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(success_connect_response.get());
// Callback for the pending id should update the connection status and send
// the D-Bus reply.
gatt_client_connect_callback(data, kTestGattClientConnectionId,
static_cast<uint8_t>(ConnectState::CONNECTED));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(success_connect_response.get());
EXPECT_EQ("", success_connect_response->GetErrorName());
// Check "connected" property value after connected.
std::unique_ptr<dbus::Response> get_property_response =
ReadProperty(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kConnectedProperty, get_property_handler,
kTestSender, kTestSerial);
dbus::MessageReader connect_message_reader(get_property_response.get());
bool connected = false;
EXPECT_TRUE(connect_message_reader.PopVariantOfBool(&connected));
EXPECT_TRUE(connected);
get_property_response.reset();
// Disconnect
dbus::MethodCall disconnect_method_call(
bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kDisconnect);
disconnect_method_call.SetSender(kTestSender);
disconnect_method_call.SetSerial(kTestSerial);
// Unknown device path
std::unique_ptr<dbus::Response> failed_disconnect_response;
disconnect_method_call.SetPath(dbus::ObjectPath(kUnknownDeviceObjectPath));
disconnect_handler.Run(
&disconnect_method_call,
base::Bind(&SaveResponse, &failed_disconnect_response));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(bluetooth_device::kErrorDoesNotExist,
failed_disconnect_response->GetErrorName());
// Disconnect succeeds by client
std::unique_ptr<dbus::Response> success_disconnect_by_client_response;
disconnect_method_call.SetPath(dbus::ObjectPath(kTestDeviceObjectPath));
disconnect_handler.Run(
&disconnect_method_call,
base::Bind(&SaveResponse, &success_disconnect_by_client_response));
gatt_client_connect_callback(
data, kTestGattClientConnectionId,
static_cast<uint8_t>(ConnectState::DISCONNECTED_BY_US));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(success_disconnect_by_client_response.get());
EXPECT_EQ("", success_disconnect_by_client_response->GetErrorName());
// Check "connected" property value after disconnected.
get_property_response =
ReadProperty(bluetooth_device::kBluetoothDeviceInterface,
bluetooth_device::kConnectedProperty, get_property_handler,
kTestSender, kTestSerial);
dbus::MessageReader disconnect_message_reader(get_property_response.get());
EXPECT_TRUE(disconnect_message_reader.PopVariantOfBool(&connected));
EXPECT_FALSE(connected);
}
void TestPair(dbus::ExportedObject::MethodCallCallback pair_handler) {
dbus::MethodCall pair_method_call(
bluetooth_device::kBluetoothDeviceInterface, bluetooth_device::kPair);
pair_method_call.SetSender(kTestSender);
pair_method_call.SetSerial(kTestSerial);
// Pair() to unknown device.
std::unique_ptr<dbus::Response> failed_pair_response;
pair_method_call.SetPath(dbus::ObjectPath(kUnknownDeviceObjectPath));
pair_handler.Run(&pair_method_call,
base::Bind(&SaveResponse, &failed_pair_response));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(failed_pair_response.get());
EXPECT_EQ(bluetooth_adapter::kErrorFailed,
failed_pair_response->GetErrorName());
// Pair() succeeds.
std::unique_ptr<dbus::Response> success_pair_response;
pair_method_call.SetPath(dbus::ObjectPath(kTestDeviceObjectPath));
EXPECT_CALL(*libnewblue_, SmPair(_, _)).Times(1);
pair_handler.Run(&pair_method_call,
base::Bind(&SaveResponse, &success_pair_response));
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(success_pair_response.get());
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
struct smPairStateChange pair_state_change = {SM_PAIR_STATE_PAIRED,
SM_PAIR_ERR_NONE, address};
(*pair_state_callback_)(pair_state_callback_data_, &pair_state_change, 1);
base::RunLoop().RunUntilIdle();
EXPECT_EQ("", success_pair_response->GetErrorName());
}
base::MessageLoop message_loop_;
scoped_refptr<dbus::MockBus> bus_;
scoped_refptr<dbus::MockObjectProxy> bluez_object_proxy_;
scoped_refptr<dbus::MockObjectProxy> bluetooth_object_proxy_;
scoped_refptr<dbus::MockObjectManager> bluez_object_manager_;
scoped_refptr<dbus::MockObjectManager> bluetooth_object_manager_;
void* pair_state_callback_data_;
smPairStateChangeCbk pair_state_callback_;
// Declare MockExportedObject's before newblue_daemon_ to make sure the
// MockExportedObject-s are destroyed after newblue_daemon_.
std::map<dbus::ObjectPath, scoped_refptr<dbus::MockExportedObject>>
mock_exported_objects_;
scoped_refptr<dbus::MockExportedObject> exported_root_object_;
scoped_refptr<dbus::MockExportedObject> exported_adapter_object_;
scoped_refptr<dbus::MockExportedObject> exported_agent_manager_object_;
std::unique_ptr<NewblueDaemon> newblue_daemon_;
MockLibNewblue* libnewblue_;
dbus::ExportedObject::MethodCallCallback dummy_method_handler_;
};
TEST_F(NewblueDaemonTest, InitFailed) {
MethodHandlerMap adapter_method_handlers;
scoped_refptr<dbus::MockExportedObject> exported_root_object =
SetupExportedRootObject();
scoped_refptr<dbus::MockExportedObject> exported_agent_manager_object =
SetupExportedAgentManagerObject();
ExpectPropertiesMethodsExported(exported_agent_manager_object,
adapter_method_handlers);
ExpectAgentManagerMethodsExported(exported_agent_manager_object);
ExpectTestInit(exported_root_object);
EXPECT_CALL(*libnewblue_, HciUp(_, _, _)).WillOnce(Return(false));
EXPECT_FALSE(newblue_daemon_->Init(
bus_, nullptr /* no need to access the delegator */));
// Shutdown now to make sure ExportedObjectManagerWrapper is destructed first
// before the mocked objects.
newblue_daemon_->Shutdown();
}
TEST_F(NewblueDaemonTest, InitSuccessAndBringUp) {
MethodHandlerMap adapter_method_handlers;
TestInit(adapter_method_handlers);
TestAdapterBringUp(exported_adapter_object_, adapter_method_handlers,
/* with_saved_devices */ true);
TestDeinit();
}
TEST_F(NewblueDaemonTest, DiscoveryAPI) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback stop_discovery_handler;
dbus::ExportedObject::MethodCallCallback remove_device_handler;
MethodHandlerMap adapter_method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_adapter::kStopDiscovery, &stop_discovery_handler},
{bluetooth_adapter::kRemoveDevice, &remove_device_handler},
};
TestInit(adapter_method_handlers);
TestAdapterBringUp(exported_adapter_object_, adapter_method_handlers,
/* with_saved_devices */ false);
ASSERT_FALSE(start_discovery_handler.is_null());
ASSERT_FALSE(stop_discovery_handler.is_null());
ASSERT_FALSE(remove_device_handler.is_null());
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath), {});
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
// Trigger the queued inquiry_response_callback task.
base::RunLoop().RunUntilIdle();
// RemoveDevice for unknown device address should do no-op and succeed.
dbus::MethodCall remove_device_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice);
ConstructRemoveDeviceMethodCall(&remove_device_method_call,
"/org/bluez/hci0/dev_11_11_11_11_11_11");
std::unique_ptr<dbus::Response> remove_device_response;
remove_device_handler.Run(&remove_device_method_call,
base::Bind(&SaveResponse, &remove_device_response));
EXPECT_EQ("", remove_device_response->GetErrorName());
// RemoveDevice successful.
dbus::MethodCall remove_device_method_call2(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice);
ConstructRemoveDeviceMethodCall(&remove_device_method_call2,
kTestDeviceObjectPath);
ExpectDeviceObjectUnexported(dbus::ObjectPath(kTestDeviceObjectPath));
std::unique_ptr<dbus::Response> remove_device_response2;
remove_device_handler.Run(
&remove_device_method_call2,
base::Bind(&SaveResponse, &remove_device_response2));
EXPECT_EQ("", remove_device_response2->GetErrorName());
RemoveMockExportedObject(dbus::ObjectPath(kTestDeviceObjectPath));
TestStopDiscovery(stop_discovery_handler);
TestDeinit();
}
TEST_F(NewblueDaemonTest, IdleMode) {
EXPECT_CALL(*bus_,
RequestOwnershipAndBlock(
newblue_object_manager::kNewblueObjectManagerServiceName,
dbus::Bus::REQUIRE_PRIMARY))
.WillOnce(Return(true));
auto libnewblue = std::make_unique<MockLibNewblue>();
libnewblue_ = libnewblue.get();
auto newblue = std::make_unique<Newblue>(std::move(libnewblue));
newblue_daemon_ = std::make_unique<NewblueDaemon>(std::move(newblue),
true /* is_idle_mode */);
// In idle mode, the daemon shouldn't try to bring up the LE stack.
EXPECT_CALL(*libnewblue_, HciUp(_, _, _)).Times(0);
EXPECT_TRUE(newblue_daemon_->Init(
bus_, nullptr /* no need to access the delegator */));
// Shutdown now to make sure ExportedObjectManagerWrapper is destructed first
// before the mocked objects.
newblue_daemon_->Shutdown();
}
TEST_F(NewblueDaemonTest, Pair) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback pair_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_device::kPair, &pair_handler},
};
TestInit(method_handlers);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ false);
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
// Trigger the queued inquiry_response_callback task.
base::RunLoop().RunUntilIdle();
TestPair(pair_handler);
TestDeinit();
}
TEST_F(NewblueDaemonTest, Connection) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback connect_handler;
dbus::ExportedObject::MethodCallCallback disconnect_handler;
dbus::ExportedObject::MethodCallCallback get_property_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_device::kConnect, &connect_handler},
{bluetooth_device::kDisconnect, &disconnect_handler},
{dbus::kPropertiesGet, &get_property_handler},
};
TestInit(method_handlers);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ true);
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
struct bt_addr address;
struct bt_addr latest_address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
ConvertToBtAddr(false, kLatestAddress, &latest_address);
(*inquiry_response_callback)(inquiry_response_callback_data, &latest_address,
&address,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
// Trigger the queued inquiry_response_callback task.
base::RunLoop().RunUntilIdle();
TestConnectDisconnect(connect_handler, disconnect_handler,
get_property_handler, &latest_address);
TestDeinit();
}
TEST_F(NewblueDaemonTest, BackgroundScan) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback stop_discovery_handler;
dbus::ExportedObject::MethodCallCallback connect_handler;
dbus::ExportedObject::MethodCallCallback disconnect_handler;
dbus::ExportedObject::MethodCallCallback pair_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_adapter::kStopDiscovery, &stop_discovery_handler},
{bluetooth_device::kConnect, &connect_handler},
{bluetooth_device::kDisconnect, &disconnect_handler},
{bluetooth_device::kPair, &pair_handler},
};
TestInit(method_handlers);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ false);
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
// Trigger the queued inquiry_response_callback task.
base::RunLoop().RunUntilIdle();
// Stop all discovery by clients so we can test background scan in isolation.
TestStopDiscovery(stop_discovery_handler);
// After the pairing is done, we should start background scan to look for the
// unconnected paired device.
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, _, _, _, _, _, _))
.WillOnce(Return(kTestDiscoveryId));
TestPair(pair_handler);
// Upon receiving an advertisement from a paired device, connection should be
// initiated.
void* data;
struct bt_addr addr;
gattCliConnectResultCbk gatt_client_connect_callback;
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _))
.WillOnce(DoAll(SaveArg<0>(&data), SaveArgPointee<1>(&addr),
SaveArg<2>(&gatt_client_connect_callback),
Return(kTestGattClientConnectionId)));
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ConvertBtAddrToString(addr), ConvertBtAddrToString(address));
// The connection succeeds, the background scan should stop
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
gatt_client_connect_callback(data, kTestGattClientConnectionId,
static_cast<uint8_t>(ConnectState::CONNECTED));
base::RunLoop().RunUntilIdle();
TestDeinit();
}
TEST_F(NewblueDaemonTest, BackgroundScanWithRandomResolvableDevice) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback stop_discovery_handler;
dbus::ExportedObject::MethodCallCallback connect_handler;
dbus::ExportedObject::MethodCallCallback disconnect_handler;
dbus::ExportedObject::MethodCallCallback pair_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_adapter::kStopDiscovery, &stop_discovery_handler},
{bluetooth_device::kConnect, &connect_handler},
{bluetooth_device::kDisconnect, &disconnect_handler},
{bluetooth_device::kPair, &pair_handler},
};
TestInit(method_handlers);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ false);
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
// Trigger the queued inquiry_response_callback task.
base::RunLoop().RunUntilIdle();
// Stop all discovery by clients so we can test background scan in isolation.
TestStopDiscovery(stop_discovery_handler);
// After the pairing is done, we should start background scan to look for the
// unconnected paired device.
EXPECT_CALL(*libnewblue_,
HciDiscoverLeStart(_, _, /* active */ false, _, _, _, _, _))
.WillOnce(Return(kTestDiscoveryId));
TestPair(pair_handler);
// Upon receiving an advertisement from a paired device, connection should be
// initiated.
void* data;
struct bt_addr addr;
struct bt_addr latest_address;
ConvertToBtAddr(false, kLatestAddress, &latest_address);
gattCliConnectResultCbk gatt_client_connect_callback;
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _))
.WillOnce(DoAll(SaveArg<0>(&data), SaveArgPointee<1>(&addr),
SaveArg<2>(&gatt_client_connect_callback),
Return(kTestGattClientConnectionId)));
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &latest_address,
&address,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ConvertBtAddrToString(addr), ConvertBtAddrToString(latest_address));
// The connection succeeds, the background scan should stop
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
gatt_client_connect_callback(data, kTestGattClientConnectionId,
static_cast<uint8_t>(ConnectState::CONNECTED));
base::RunLoop().RunUntilIdle();
TestDeinit();
}
TEST_F(NewblueDaemonTest, ScanState) {
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback stop_discovery_handler;
dbus::ExportedObject::MethodCallCallback suspend_imminent_handler;
dbus::ExportedObject::MethodCallCallback suspend_done_handler;
dbus::ExportedObject::MethodCallCallback pair_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_adapter::kStopDiscovery, &stop_discovery_handler},
{bluetooth_adapter::kHandleSuspendImminent, &suspend_imminent_handler},
{bluetooth_adapter::kHandleSuspendDone, &suspend_done_handler},
{bluetooth_device::kPair, &pair_handler},
};
TestInit(method_handlers);
// With previously paired device, background scan should start
EXPECT_CALL(*libnewblue_, HciDiscoverLeStart(_, _, _, _, _, _, _, _))
.Times(0);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ false);
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
// Two clients will request start discovery.
TestStartDiscovery(start_discovery_handler, &inquiry_response_callback,
&inquiry_response_callback_data);
// Device discovered.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
struct bt_addr address;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// Paired with the device
TestPair(pair_handler);
base::RunLoop().RunUntilIdle();
// Trigger suspend imminent, all discovery activities should stop
dbus::MethodCall suspend_imminent_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kHandleSuspendImminent);
suspend_imminent_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
suspend_imminent_method_call.SetSender(kTestSender);
suspend_imminent_method_call.SetSerial(kTestSerial);
// Add action (empty string)
dbus::MessageWriter suspendWriter(&suspend_imminent_method_call);
suspendWriter.AppendString("");
std::unique_ptr<dbus::Response> suspend_imminent_response;
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
suspend_imminent_handler.Run(
&suspend_imminent_method_call,
base::Bind(&SaveResponse, &suspend_imminent_response));
base::RunLoop().RunUntilIdle();
// System wake up, expect active discovery to be resumed
dbus::MethodCall suspend_done_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kHandleSuspendDone);
suspend_done_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
suspend_done_method_call.SetSender(kTestSender);
suspend_done_method_call.SetSerial(kTestSerial);
// Add action (empty string)
dbus::MessageWriter doneWriter(&suspend_done_method_call);
doneWriter.AppendString("");
std::unique_ptr<dbus::Response> suspend_done_response;
EXPECT_CALL(*libnewblue_,
HciDiscoverLeStart(_, _, /* active */ true, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kTestDiscoveryId)));
suspend_done_handler.Run(&suspend_done_method_call,
base::Bind(&SaveResponse, &suspend_done_response));
base::RunLoop().RunUntilIdle();
// Stop discovery, however passive scan should resume because not all paired
// device is connected. There two clients having discovery session now.
dbus::MethodCall stop_discovery_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery);
stop_discovery_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
stop_discovery_method_call.SetSender(kTestSender);
stop_discovery_method_call.SetSerial(kTestSerial);
std::unique_ptr<dbus::Response> stop_discovery_response;
// Stop the first clients.
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
// Stop discovery for second clients.
stop_discovery_method_call.SetSender(kTestSender2);
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
EXPECT_CALL(*libnewblue_,
HciDiscoverLeStart(_, _, /* active */ false, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kTestDiscoveryId)));
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
base::RunLoop().RunUntilIdle();
// Upon receiving an advertisement from a paired device, connection should be
// initiated.
void* data;
gattCliConnectResultCbk gatt_client_connect_callback;
EXPECT_CALL(*libnewblue_, GattClientConnect(_, _, _))
.WillOnce(DoAll(SaveArg<0>(&data),
SaveArg<2>(&gatt_client_connect_callback),
Return(kTestGattClientConnectionId)));
ConvertToBtAddr(false, kTestDeviceAddress, &address);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -101, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ {},
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// The connection succeeds, the background scan should stop
EXPECT_CALL(*libnewblue_, HciDiscoverLeStop(kTestDiscoveryId))
.WillOnce(Return(true));
gatt_client_connect_callback(data, kTestGattClientConnectionId,
static_cast<uint8_t>(ConnectState::CONNECTED));
base::RunLoop().RunUntilIdle();
TestDeinit();
}
TEST_F(NewblueDaemonTest, DiscoveryFilter) {
dbus::ExportedObject::MethodCallCallback set_discovery_filter_handler;
dbus::ExportedObject::MethodCallCallback start_discovery_handler;
dbus::ExportedObject::MethodCallCallback stop_discovery_handler;
dbus::ExportedObject::MethodCallCallback remove_device_handler;
MethodHandlerMap method_handlers = {
{bluetooth_adapter::kSetDiscoveryFilter, &set_discovery_filter_handler},
{bluetooth_adapter::kStartDiscovery, &start_discovery_handler},
{bluetooth_adapter::kStopDiscovery, &stop_discovery_handler},
{bluetooth_adapter::kRemoveDevice, &remove_device_handler},
};
TestInit(method_handlers);
TestAdapterBringUp(exported_adapter_object_, method_handlers,
/* with_saved_devices */ false);
// Initialization.
dbus::MethodCall start_discovery_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStartDiscovery);
start_discovery_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
start_discovery_method_call.SetSender(kTestSender);
start_discovery_method_call.SetSerial(kTestSerial);
std::unique_ptr<dbus::Response> start_discovery_response;
dbus::MethodCall stop_discovery_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery);
stop_discovery_method_call.SetPath(dbus::ObjectPath(kAdapterObjectPath));
stop_discovery_method_call.SetSender(kTestSender);
stop_discovery_method_call.SetSerial(kTestSerial);
std::unique_ptr<dbus::Response> stop_discovery_response;
Newblue::DeviceDiscoveredCallback on_device_discovered;
hciDeviceDiscoveredLeCbk inquiry_response_callback;
void* inquiry_response_callback_data;
struct bt_addr address, address2;
ConvertToBtAddr(false, kTestDeviceAddress, &address);
ConvertToBtAddr(false, kTestDeviceAddress2, &address2);
// Setup the discovery filter to filter out low RSSI devices.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"tight");
// Start discovery
EXPECT_CALL(*libnewblue_,
HciDiscoverLeStart(_, _, /* active */ true, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(&inquiry_response_callback),
SaveArg<1>(&inquiry_response_callback_data),
Return(kTestDiscoveryId)));
start_discovery_handler.Run(
&start_discovery_method_call,
base::Bind(&SaveResponse, &start_discovery_response));
// Both devices are blocked by the "tight" filter.
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath));
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
// Update the filter for the same client.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"classic_loose");
// Both devices are still blocked because the latest filter is for classic
// only and ignored by NewBlue.
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath));
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
// Setup the discovery filter to have slightly lower RSSI threshold.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"looser_rssi");
// One device with higher RSSI shall pass, but not the second one.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// Clear the filter for the client by sending an empty filter dict.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"clear");
// The second device with lower RSSI shall pass now.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath2),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// Remove both discovered devices for the following tests.
dbus::MethodCall remove_device_method_call(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice);
ConstructRemoveDeviceMethodCall(&remove_device_method_call,
kTestDeviceObjectPath);
ExpectDeviceObjectUnexported(dbus::ObjectPath(kTestDeviceObjectPath));
std::unique_ptr<dbus::Response> remove_device_response;
remove_device_handler.Run(&remove_device_method_call,
base::Bind(&SaveResponse, &remove_device_response));
RemoveMockExportedObject(dbus::ObjectPath(kTestDeviceObjectPath));
dbus::MethodCall remove_device_method_call2(
bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice);
ConstructRemoveDeviceMethodCall(&remove_device_method_call2,
kTestDeviceObjectPath2);
ExpectDeviceObjectUnexported(dbus::ObjectPath(kTestDeviceObjectPath2));
std::unique_ptr<dbus::Response> remove_device_response2;
remove_device_handler.Run(
&remove_device_method_call2,
base::Bind(&SaveResponse, &remove_device_response2));
RemoveMockExportedObject(dbus::ObjectPath(kTestDeviceObjectPath2));
// Setup the discovery filter to looking for a wrong UUID.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"uuid");
// Both devices are blocked by the "uuid filter".
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath));
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
// Setup a looser RSSI with correct uuid filter by second client. However,
// since second client have not started a scan session. No effect on filters.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender2,
"looser_rssi");
// Both devices are still blocked by the "uuid filter".
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath));
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
// Try start discovery by the second client. Now the filters will merge to
// become a "looser RSSI filter" to allow one device to pass.
start_discovery_method_call.SetSender(kTestSender2);
start_discovery_handler.Run(
&start_discovery_method_call,
base::Bind(&SaveResponse, &start_discovery_response));
// One device with higher RSSI shall pass, but not the second one.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
// Update the filter for first client to be loose. The other device should
// pass now.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender,
"loose");
// The second device with lower RSSI shall pass now.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath2),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// Remove both discovered devices for the following tests.
ExpectDeviceObjectUnexported(dbus::ObjectPath(kTestDeviceObjectPath));
remove_device_handler.Run(&remove_device_method_call,
base::Bind(&SaveResponse, &remove_device_response));
RemoveMockExportedObject(dbus::ObjectPath(kTestDeviceObjectPath));
ExpectDeviceObjectUnexported(dbus::ObjectPath(kTestDeviceObjectPath2));
remove_device_handler.Run(
&remove_device_method_call2,
base::Bind(&SaveResponse, &remove_device_response2));
RemoveMockExportedObject(dbus::ObjectPath(kTestDeviceObjectPath2));
// Try stop discovery by the first client. Now the merged filter will back to
// what second client holds: a "looser_rssi" filter.
stop_discovery_handler.Run(
&stop_discovery_method_call,
base::Bind(&SaveResponse, &stop_discovery_response));
// One device with higher RSSI shall pass, but not the second one.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address,
/* resolved_address */ nullptr,
/* rssi */ -90, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ sizeof(eir));
base::RunLoop().RunUntilIdle();
ExpectDeviceObjectNotExported(dbus::ObjectPath(kTestDeviceObjectPath2));
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
// Clear the filter for the second client by sending an empty filter dict.
CallSetDiscoveryFilterMethod(set_discovery_filter_handler, kTestSender2,
"clear");
// The second device with lower RSSI shall pass now.
ExpectDeviceObjectExported(dbus::ObjectPath(kTestDeviceObjectPath2),
method_handlers);
(*inquiry_response_callback)(inquiry_response_callback_data, &address2,
/* resolved_address */ nullptr,
/* rssi */ -110, HCI_ADV_TYPE_SCAN_RSP,
/* eir */ eir,
/* eir_len*/ 0);
base::RunLoop().RunUntilIdle();
TestDeinit();
}
// TODO(mcchou): Add a test case where the connection is terminated by remote
// device.
} // namespace bluetooth