blob: b0fae11bff0177a2aafe205390eab3259171fb21 [file] [log] [blame]
// Copyright 2019 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 <memory>
#include <string>
#include <vector>
#include <base/bind.h>
#include <base/memory/ref_counted.h>
#include <base/run_loop.h>
#include <base/test/task_environment.h>
#include <base/threading/thread_task_runner_handle.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_object_manager.h>
#include <dbus/mock_object_proxy.h>
#include <dbus/bluetooth/dbus-constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "diagnostics/common/system/bluetooth_client.h"
#include "diagnostics/common/system/bluetooth_client_impl.h"
using ::testing::_;
using ::testing::ElementsAreArray;
using ::testing::Mock;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrictMock;
namespace diagnostics {
namespace {
const dbus::ObjectPath kAdapterPath("/org/bluez/hci0");
const dbus::ObjectPath kDevicePath("/org/bluez/hci0/dev_70_88_6B_92_34_70");
void PropertyChanged(const std::string& property_name) {}
std::unique_ptr<BluetoothClient::AdapterProperties> GetAdapterProperties() {
auto properties = std::make_unique<BluetoothClient::AdapterProperties>(
nullptr, base::Bind(&PropertyChanged));
properties->address.ReplaceValue("aa:bb:cc:dd:ee:ff");
properties->name.ReplaceValue("sarien-laptop");
properties->powered.ReplaceValue(true);
properties->address.set_valid(true);
properties->name.set_valid(true);
properties->powered.set_valid(true);
return properties;
}
std::unique_ptr<BluetoothClient::DeviceProperties> GetDeviceProperties() {
auto properties = std::make_unique<BluetoothClient::DeviceProperties>(
nullptr, base::Bind(&PropertyChanged));
properties->address.ReplaceValue("70:88:6B:92:34:70");
properties->name.ReplaceValue("GID6B");
properties->connected.ReplaceValue(true);
properties->address.set_valid(true);
properties->name.set_valid(true);
properties->connected.set_valid(true);
return properties;
}
MATCHER_P(AdapterPropertiesEquals, expected_properties, "") {
return arg.address.value() == expected_properties->address.value() &&
arg.name.value() == expected_properties->name.value() &&
arg.powered.value() == expected_properties->powered.value();
}
MATCHER_P(DevicePropertiesEquals, expected_properties, "") {
return arg.address.value() == expected_properties->address.value() &&
arg.name.value() == expected_properties->name.value() &&
arg.connected.value() == expected_properties->connected.value();
}
class MockBluetoothClientObserver : public BluetoothClient::Observer {
public:
MOCK_METHOD(void,
AdapterAdded,
(const dbus::ObjectPath& object_path,
const BluetoothClient::AdapterProperties& properties));
MOCK_METHOD(void, AdapterRemoved, (const dbus::ObjectPath& object_path));
MOCK_METHOD(void,
AdapterPropertyChanged,
(const dbus::ObjectPath& object_path,
const BluetoothClient::AdapterProperties& properties));
MOCK_METHOD(void,
DeviceAdded,
(const dbus::ObjectPath& object_path,
const BluetoothClient::DeviceProperties& properties));
MOCK_METHOD(void, DeviceRemoved, (const dbus::ObjectPath& object_path));
MOCK_METHOD(void,
DevicePropertyChanged,
(const dbus::ObjectPath& object_path,
const BluetoothClient::DeviceProperties& properties));
};
} // namespace
class BluetoothClientImplTest : public ::testing::Test {
public:
BluetoothClientImplTest()
: dbus_bus_(new dbus::MockBus(dbus::Bus::Options())),
dbus_object_proxy_(new dbus::MockObjectProxy(
dbus_bus_.get(),
bluez_object_manager::kBluezObjectManagerServiceName,
dbus::ObjectPath(
bluez_object_manager::kBluezObjectManagerServicePath))) {}
BluetoothClientImplTest(const BluetoothClientImplTest&) = delete;
BluetoothClientImplTest& operator=(const BluetoothClientImplTest&) = delete;
~BluetoothClientImplTest() override {
EXPECT_CALL(
*dbus_object_manager_,
UnregisterInterface(bluetooth_adapter::kBluetoothAdapterInterface));
EXPECT_CALL(
*dbus_object_manager_,
UnregisterInterface(bluetooth_device::kBluetoothDeviceInterface));
}
void SetUp() override {
ON_CALL(*dbus_bus_, GetDBusTaskRunner())
.WillByDefault(Return(base::ThreadTaskRunnerHandle::Get().get()));
EXPECT_CALL(*dbus_bus_,
GetObjectProxy(
bluez_object_manager::kBluezObjectManagerServiceName,
dbus::ObjectPath(
bluez_object_manager::kBluezObjectManagerServicePath)))
.WillOnce(Return(dbus_object_proxy_.get()));
dbus_object_manager_ = new StrictMock<dbus::MockObjectManager>(
dbus_bus_.get(), bluez_object_manager::kBluezObjectManagerServiceName,
dbus::ObjectPath(bluez_object_manager::kBluezObjectManagerServicePath));
// Force TaskRunner to run pending tasks as effect of instantiating
// MockObjectManager. Needed to avoid memory leaks because pending tasks
// are unowned pointers that will only self destruct after being run.
base::RunLoop run_loop;
run_loop.RunUntilIdle();
EXPECT_CALL(*dbus_bus_,
GetObjectManager(
bluez_object_manager::kBluezObjectManagerServiceName,
dbus::ObjectPath(
bluez_object_manager::kBluezObjectManagerServicePath)))
.WillOnce(Return(dbus_object_manager_.get()));
EXPECT_CALL(*dbus_object_manager_,
RegisterInterface(bluetooth_adapter::kBluetoothAdapterInterface,
NotNull()))
.WillOnce(SaveArg<1>(&adapter_manager_interface_));
EXPECT_CALL(*dbus_object_manager_,
RegisterInterface(bluetooth_device::kBluetoothDeviceInterface,
NotNull()))
.WillOnce(SaveArg<1>(&device_manager_interface_));
bluetooth_client_ = std::make_unique<BluetoothClientImpl>(dbus_bus_);
ASSERT_TRUE(Mock::VerifyAndClearExpectations(dbus_bus_.get()));
ASSERT_TRUE(Mock::VerifyAndClearExpectations(dbus_object_manager_.get()));
bluetooth_client_->AddObserver(&observer_);
}
MockBluetoothClientObserver* observer() { return &observer_; }
dbus::MockObjectManager* object_manager() {
return dbus_object_manager_.get();
}
dbus::ObjectManager::Interface* adapter_manager_interface() {
return adapter_manager_interface_;
}
dbus::ObjectManager::Interface* device_manager_interface() {
return device_manager_interface_;
}
BluetoothClient* bluetooth_client() const { return bluetooth_client_.get(); }
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY};
StrictMock<MockBluetoothClientObserver> observer_;
scoped_refptr<dbus::MockBus> dbus_bus_;
scoped_refptr<dbus::MockObjectProxy> dbus_object_proxy_;
scoped_refptr<StrictMock<dbus::MockObjectManager>> dbus_object_manager_;
std::unique_ptr<BluetoothClientImpl> bluetooth_client_;
// Not owned. Pointers passed by |bluetooth_client_| to
// |dbus_object_manager_|.
dbus::ObjectManager::Interface* adapter_manager_interface_;
dbus::ObjectManager::Interface* device_manager_interface_;
};
TEST_F(BluetoothClientImplTest, GetAdapters) {
const std::vector<dbus::ObjectPath> kAdapterPaths = {kAdapterPath};
EXPECT_CALL(
*object_manager(),
GetObjectsWithInterface(bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(kAdapterPaths));
std::vector<dbus::ObjectPath> adapter_paths =
bluetooth_client()->GetAdapters();
EXPECT_THAT(adapter_paths, ElementsAreArray(kAdapterPaths));
}
TEST_F(BluetoothClientImplTest, GetDevices) {
const std::vector<dbus::ObjectPath> kDevicePaths = {kDevicePath};
EXPECT_CALL(
*object_manager(),
GetObjectsWithInterface(bluetooth_device::kBluetoothDeviceInterface))
.WillOnce(Return(kDevicePaths));
std::vector<dbus::ObjectPath> device_paths = bluetooth_client()->GetDevices();
EXPECT_THAT(device_paths, ElementsAreArray(kDevicePaths));
}
TEST_F(BluetoothClientImplTest, GetAdapterProperties) {
const auto kProperties = GetAdapterProperties();
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(kProperties.get()));
auto adapter_properties =
bluetooth_client()->GetAdapterProperties(kAdapterPath);
ASSERT_TRUE(adapter_properties);
EXPECT_THAT(*adapter_properties, AdapterPropertiesEquals(kProperties.get()));
}
TEST_F(BluetoothClientImplTest, GetAdapterPropertiesNullProperties) {
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(nullptr));
EXPECT_FALSE(bluetooth_client()->GetAdapterProperties(kAdapterPath));
}
TEST_F(BluetoothClientImplTest, GetAdapterPropertiesInvalidProperties) {
auto properties = GetAdapterProperties();
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.Times(4)
.WillRepeatedly(Return(properties.get()));
properties->address.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetAdapterProperties(kAdapterPath));
properties->address.set_valid(true);
properties->name.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetAdapterProperties(kAdapterPath));
properties->name.set_valid(true);
properties->powered.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetAdapterProperties(kAdapterPath));
properties->powered.set_valid(true);
auto adapter_properties =
bluetooth_client()->GetAdapterProperties(kAdapterPath);
ASSERT_TRUE(adapter_properties);
EXPECT_THAT(*adapter_properties, AdapterPropertiesEquals(properties.get()));
}
TEST_F(BluetoothClientImplTest, GetDeviceProperties) {
const auto kProperties = GetDeviceProperties();
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.WillOnce(Return(kProperties.get()));
auto device_properties = bluetooth_client()->GetDeviceProperties(kDevicePath);
ASSERT_TRUE(device_properties);
EXPECT_THAT(*device_properties, DevicePropertiesEquals(kProperties.get()));
}
TEST_F(BluetoothClientImplTest, GetDevicePropertiesNullProperties) {
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.WillOnce(Return(nullptr));
EXPECT_FALSE(bluetooth_client()->GetDeviceProperties(kDevicePath));
}
TEST_F(BluetoothClientImplTest, GetDevicePropertiesInvalidProperties) {
auto properties = GetDeviceProperties();
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.Times(4)
.WillRepeatedly(Return(properties.get()));
properties->address.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetDeviceProperties(kDevicePath));
properties->address.set_valid(true);
properties->name.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetDeviceProperties(kDevicePath));
properties->name.set_valid(true);
properties->connected.set_valid(false);
EXPECT_FALSE(bluetooth_client()->GetDeviceProperties(kDevicePath));
properties->connected.set_valid(true);
auto device_properties = bluetooth_client()->GetDeviceProperties(kDevicePath);
ASSERT_TRUE(device_properties);
EXPECT_THAT(*device_properties, DevicePropertiesEquals(properties.get()));
}
TEST_F(BluetoothClientImplTest, AdapterAddedNullProperties) {
EXPECT_CALL(*object_manager(), GetProperties(kAdapterPath, _))
.WillOnce(Return(nullptr));
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
}
TEST_F(BluetoothClientImplTest, AdapterAddedWithInvalidProperties) {
auto adapter_properties = GetAdapterProperties();
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.Times(3)
.WillRepeatedly(Return(adapter_properties.get()));
adapter_properties->address.set_valid(false);
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
adapter_properties->address.set_valid(true);
adapter_properties->name.set_valid(false);
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
adapter_properties->name.set_valid(true);
adapter_properties->powered.set_valid(false);
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
adapter_properties->powered.set_valid(true);
}
TEST_F(BluetoothClientImplTest, AdapterAdded) {
const auto kProperties = GetAdapterProperties();
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(kProperties.get()));
EXPECT_CALL(
*observer(),
AdapterAdded(kAdapterPath, AdapterPropertiesEquals(kProperties.get())));
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
}
TEST_F(BluetoothClientImplTest, AdapterRemoved) {
EXPECT_CALL(*observer(), AdapterRemoved(kAdapterPath));
adapter_manager_interface()->ObjectRemoved(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
}
TEST_F(BluetoothClientImplTest, AdapterPropertyChangedNullProperties) {
dbus::PropertySet* properties_base_ptr =
adapter_manager_interface()->CreateProperties(
nullptr, kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
ASSERT_TRUE(properties_base_ptr);
std::unique_ptr<BluetoothClient::AdapterProperties> properties(
static_cast<BluetoothClient::AdapterProperties*>(properties_base_ptr));
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(nullptr));
properties->powered.ReplaceValue(true);
}
TEST_F(BluetoothClientImplTest, AdapterPropertyChanged) {
dbus::PropertySet* properties_base_ptr =
adapter_manager_interface()->CreateProperties(
nullptr, kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
ASSERT_TRUE(properties_base_ptr);
std::unique_ptr<BluetoothClient::AdapterProperties> properties(
static_cast<BluetoothClient::AdapterProperties*>(properties_base_ptr));
properties->address.set_valid(true);
properties->name.set_valid(true);
properties->powered.set_valid(true);
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.Times(4)
.WillRepeatedly(Return(properties_base_ptr));
properties->address.set_valid(false);
properties->address.ReplaceValue("aa:aa:aa:ff:ff:ff");
properties->address.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
properties->name.set_valid(false);
properties->name.ReplaceValue("sarien-laptop");
properties->name.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
properties->powered.set_valid(false);
properties->powered.ReplaceValue(true);
properties->powered.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
EXPECT_CALL(*observer(),
AdapterPropertyChanged(
kAdapterPath, AdapterPropertiesEquals(properties.get())));
properties->address.ReplaceValue("ff:ff:ff:aa:aa:aa");
}
TEST_F(BluetoothClientImplTest, DeviceAddedNullProperties) {
EXPECT_CALL(*object_manager(), GetProperties(kDevicePath, _))
.WillOnce(Return(nullptr));
device_manager_interface()->ObjectAdded(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
}
TEST_F(BluetoothClientImplTest, DeviceAddedWithInvalidProperties) {
auto device_properties = GetDeviceProperties();
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.Times(3)
.WillRepeatedly(Return(device_properties.get()));
device_properties->address.set_valid(false);
device_manager_interface()->ObjectAdded(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
device_properties->address.set_valid(true);
device_properties->name.set_valid(false);
device_manager_interface()->ObjectAdded(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
device_properties->name.set_valid(true);
device_properties->connected.set_valid(false);
device_manager_interface()->ObjectAdded(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
device_properties->connected.set_valid(true);
}
TEST_F(BluetoothClientImplTest, DeviceAdded) {
const auto kProperties = GetDeviceProperties();
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.WillOnce(Return(kProperties.get()));
EXPECT_CALL(
*observer(),
DeviceAdded(kDevicePath, DevicePropertiesEquals(kProperties.get())));
device_manager_interface()->ObjectAdded(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
}
TEST_F(BluetoothClientImplTest, DeviceRemoved) {
const auto kProperties = GetDeviceProperties();
EXPECT_CALL(*observer(), DeviceRemoved(kDevicePath));
device_manager_interface()->ObjectRemoved(
kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
}
TEST_F(BluetoothClientImplTest, DevicePropertyChangedNullProperties) {
dbus::PropertySet* properties_base_ptr =
device_manager_interface()->CreateProperties(
nullptr, kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
ASSERT_TRUE(properties_base_ptr);
std::unique_ptr<BluetoothClient::DeviceProperties> properties(
static_cast<BluetoothClient::DeviceProperties*>(properties_base_ptr));
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.WillOnce(Return(nullptr));
properties->connected.ReplaceValue(true);
}
TEST_F(BluetoothClientImplTest, DevicePropertyChanged) {
dbus::PropertySet* properties_base_ptr =
device_manager_interface()->CreateProperties(
nullptr, kDevicePath, bluetooth_device::kBluetoothDeviceInterface);
ASSERT_TRUE(properties_base_ptr);
std::unique_ptr<BluetoothClient::DeviceProperties> properties(
static_cast<BluetoothClient::DeviceProperties*>(properties_base_ptr));
properties->address.set_valid(true);
properties->name.set_valid(true);
properties->connected.set_valid(true);
EXPECT_CALL(
*object_manager(),
GetProperties(kDevicePath, bluetooth_device::kBluetoothDeviceInterface))
.Times(4)
.WillRepeatedly(Return(properties_base_ptr));
properties->address.set_valid(false);
properties->address.ReplaceValue("ff:ff:ff:aa:aa:aa");
properties->address.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
properties->name.set_valid(false);
properties->name.ReplaceValue("GID6");
properties->name.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
properties->connected.set_valid(false);
properties->connected.ReplaceValue(true);
properties->connected.set_valid(true);
Mock::VerifyAndClearExpectations(observer());
EXPECT_CALL(*observer(),
DevicePropertyChanged(kDevicePath,
DevicePropertiesEquals(properties.get())));
properties->address.ReplaceValue("aa:aa:aa:ff:ff:ff");
}
TEST_F(BluetoothClientImplTest, AddAndRemoveObserver) {
const auto kProperties = GetAdapterProperties();
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(kProperties.get()));
EXPECT_CALL(
*observer(),
AdapterAdded(kAdapterPath, AdapterPropertiesEquals(kProperties.get())));
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
bluetooth_client()->RemoveObserver(observer());
EXPECT_CALL(*object_manager(),
GetProperties(kAdapterPath,
bluetooth_adapter::kBluetoothAdapterInterface))
.WillOnce(Return(kProperties.get()));
adapter_manager_interface()->ObjectAdded(
kAdapterPath, bluetooth_adapter::kBluetoothAdapterInterface);
}
} // namespace diagnostics