// Copyright 2013 The Chromium 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 #include #include #include "base/bind_helpers.h" #include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "dbus/object_path.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter_bluez.h" #include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_device_bluez.h" #include "device/bluetooth/bluetooth_discovery_session.h" #include "device/bluetooth/bluetooth_pairing_bluez.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h" #include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h" #include "device/bluetooth/dbus/fake_bluetooth_device_client.h" #include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h" #include "device/bluetooth/dbus/fake_bluetooth_input_client.h" #include "device/bluetooth/test/test_bluetooth_adapter_observer.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/cros_system_api/dbus/service_constants.h" using device::BluetoothAdapter; using device::BluetoothAdapterFactory; using device::BluetoothAudioSink; using device::BluetoothDevice; using device::BluetoothDiscoveryFilter; using device::BluetoothDiscoverySession; using device::BluetoothUUID; using device::TestBluetoothAdapterObserver; namespace bluez { namespace { // Callback for BluetoothDevice::GetConnectionInfo() that simply saves the // connection info to the bound argument. void SaveConnectionInfo(BluetoothDevice::ConnectionInfo* out, const BluetoothDevice::ConnectionInfo& conn_info) { *out = conn_info; }; // Find |address| in |devices|, if found returns the index otherwise returns -1. int GetDeviceIndexByAddress(BluetoothAdapter::DeviceList& devices, const char* address) { int idx = -1; for (auto& device : devices) { ++idx; if (device->GetAddress().compare(address) == 0) return idx; } return -1; } class FakeBluetoothProfileServiceProviderDelegate : public bluez::BluetoothProfileServiceProvider::Delegate { public: FakeBluetoothProfileServiceProviderDelegate() {} // bluez::BluetoothProfileServiceProvider::Delegate: void Released() override {} void NewConnection( const dbus::ObjectPath&, scoped_ptr, const bluez::BluetoothProfileServiceProvider::Delegate::Options&, const ConfirmationCallback&) override {} void RequestDisconnection(const dbus::ObjectPath&, const ConfirmationCallback&) override {} void Cancel() override {} }; } // namespace class TestPairingDelegate : public BluetoothDevice::PairingDelegate { public: TestPairingDelegate() : call_count_(0), request_pincode_count_(0), request_passkey_count_(0), display_pincode_count_(0), display_passkey_count_(0), keys_entered_count_(0), confirm_passkey_count_(0), authorize_pairing_count_(0), last_passkey_(9999999U), last_entered_(999U) {} ~TestPairingDelegate() override {} void RequestPinCode(BluetoothDevice* device) override { ++call_count_; ++request_pincode_count_; QuitMessageLoop(); } void RequestPasskey(BluetoothDevice* device) override { ++call_count_; ++request_passkey_count_; QuitMessageLoop(); } void DisplayPinCode(BluetoothDevice* device, const std::string& pincode) override { ++call_count_; ++display_pincode_count_; last_pincode_ = pincode; QuitMessageLoop(); } void DisplayPasskey(BluetoothDevice* device, uint32_t passkey) override { ++call_count_; ++display_passkey_count_; last_passkey_ = passkey; QuitMessageLoop(); } void KeysEntered(BluetoothDevice* device, uint32_t entered) override { ++call_count_; ++keys_entered_count_; last_entered_ = entered; QuitMessageLoop(); } void ConfirmPasskey(BluetoothDevice* device, uint32_t passkey) override { ++call_count_; ++confirm_passkey_count_; last_passkey_ = passkey; QuitMessageLoop(); } void AuthorizePairing(BluetoothDevice* device) override { ++call_count_; ++authorize_pairing_count_; QuitMessageLoop(); } int call_count_; int request_pincode_count_; int request_passkey_count_; int display_pincode_count_; int display_passkey_count_; int keys_entered_count_; int confirm_passkey_count_; int authorize_pairing_count_; uint32_t last_passkey_; uint32_t last_entered_; std::string last_pincode_; private: // Some tests use a message loop since background processing is simulated; // break out of those loops. void QuitMessageLoop() { if (base::MessageLoop::current() && base::MessageLoop::current()->is_running()) { base::MessageLoop::current()->QuitWhenIdle(); } } }; class BluetoothBlueZTest : public testing::Test { public: void SetUp() override { scoped_ptr dbus_setter = bluez::BluezDBusManager::GetSetterForTesting(); // We need to initialize BluezDBusManager early to prevent // Bluetooth*::Create() methods from picking the real instead of fake // implementations. fake_bluetooth_adapter_client_ = new bluez::FakeBluetoothAdapterClient; dbus_setter->SetBluetoothAdapterClient( scoped_ptr( fake_bluetooth_adapter_client_)); fake_bluetooth_device_client_ = new bluez::FakeBluetoothDeviceClient; // Use the original fake behavior for these tests. fake_bluetooth_device_client_->set_delay_start_discovery(true); dbus_setter->SetBluetoothDeviceClient( scoped_ptr( fake_bluetooth_device_client_)); dbus_setter->SetBluetoothInputClient( scoped_ptr( new bluez::FakeBluetoothInputClient)); dbus_setter->SetBluetoothAgentManagerClient( scoped_ptr( new bluez::FakeBluetoothAgentManagerClient)); dbus_setter->SetBluetoothGattServiceClient( scoped_ptr( new bluez::FakeBluetoothGattServiceClient)); fake_bluetooth_adapter_client_->SetSimulationIntervalMs(10); callback_count_ = 0; error_callback_count_ = 0; last_connect_error_ = BluetoothDevice::ERROR_UNKNOWN; last_client_error_ = ""; } void TearDown() override { for (ScopedVector::iterator iter = discovery_sessions_.begin(); iter != discovery_sessions_.end(); ++iter) { BluetoothDiscoverySession* session = *iter; if (!session->IsActive()) continue; callback_count_ = 0; session->Stop(GetCallback(), GetErrorCallback()); message_loop_.Run(); ASSERT_EQ(1, callback_count_); } discovery_sessions_.clear(); adapter_ = nullptr; bluez::BluezDBusManager::Shutdown(); } // Generic callbacks void Callback() { ++callback_count_; QuitMessageLoop(); } base::Closure GetCallback() { return base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)); } void AdapterCallback() { QuitMessageLoop(); } void DiscoverySessionCallback( scoped_ptr discovery_session) { ++callback_count_; discovery_sessions_.push_back(discovery_session.release()); QuitMessageLoop(); } void AudioSinkAcquiredCallback(scoped_refptr) { ++callback_count_; QuitMessageLoop(); } void ProfileRegisteredCallback(BluetoothAdapterProfileBlueZ* profile) { adapter_profile_ = profile; ++callback_count_; QuitMessageLoop(); } void ErrorCallback() { ++error_callback_count_; QuitMessageLoop(); } void DiscoveryErrorCallback(device::UMABluetoothDiscoverySessionOutcome) { ErrorCallback(); } base::Closure GetErrorCallback() { return base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this)); } base::Callback GetDiscoveryErrorCallback() { return base::Bind(&BluetoothBlueZTest::DiscoveryErrorCallback, base::Unretained(this)); } void DBusErrorCallback(const std::string& error_name, const std::string& error_message) { ++error_callback_count_; last_client_error_ = error_name; QuitMessageLoop(); } void ConnectErrorCallback(BluetoothDevice::ConnectErrorCode error) { ++error_callback_count_; last_connect_error_ = error; } void AudioSinkErrorCallback(BluetoothAudioSink::ErrorCode) { ++error_callback_count_; QuitMessageLoop(); } void ErrorCompletionCallback(const std::string& error_message) { ++error_callback_count_; QuitMessageLoop(); } // Call to fill the adapter_ member with a BluetoothAdapter instance. void GetAdapter() { adapter_ = new BluetoothAdapterBlueZ(base::Bind( &BluetoothBlueZTest::AdapterCallback, base::Unretained(this))); base::MessageLoop::current()->Run(); ASSERT_TRUE(adapter_.get() != nullptr); ASSERT_TRUE(adapter_->IsInitialized()); } // Run a discovery phase until the named device is detected, or if the named // device is not created, the discovery process ends without finding it. // // The correct behavior of discovery is tested by the "Discovery" test case // without using this function. void DiscoverDevice(const std::string& address) { ASSERT_TRUE(adapter_.get() != nullptr); ASSERT_TRUE(base::MessageLoop::current() != nullptr); fake_bluetooth_device_client_->SetSimulationIntervalMs(10); TestBluetoothAdapterObserver observer(adapter_); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); base::MessageLoop::current()->Run(); ASSERT_EQ(2, callback_count_); ASSERT_EQ(0, error_callback_count_); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); while (!observer.device_removed_count() && observer.last_device_address() != address) base::MessageLoop::current()->Run(); discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); base::MessageLoop::current()->Run(); ASSERT_EQ(1, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_FALSE(adapter_->IsDiscovering()); } // Run a discovery phase so we have devices that can be paired with. void DiscoverDevices() { // Pass an invalid address for the device so that the discovery process // completes with all devices. DiscoverDevice("does not exist"); } protected: base::MessageLoop message_loop_; bluez::FakeBluetoothAdapterClient* fake_bluetooth_adapter_client_; bluez::FakeBluetoothDeviceClient* fake_bluetooth_device_client_; scoped_refptr adapter_; int callback_count_; int error_callback_count_; enum BluetoothDevice::ConnectErrorCode last_connect_error_; std::string last_client_error_; ScopedVector discovery_sessions_; BluetoothAdapterProfileBlueZ* adapter_profile_; private: // Some tests use a message loop since background processing is simulated; // break out of those loops. void QuitMessageLoop() { if (base::MessageLoop::current() && base::MessageLoop::current()->is_running()) { base::MessageLoop::current()->QuitWhenIdle(); } } }; TEST_F(BluetoothBlueZTest, AlreadyPresent) { GetAdapter(); // This verifies that the class gets the list of adapters when created; // and initializes with an existing adapter if there is one. EXPECT_TRUE(adapter_->IsPresent()); EXPECT_FALSE(adapter_->IsPowered()); EXPECT_EQ(bluez::FakeBluetoothAdapterClient::kAdapterAddress, adapter_->GetAddress()); EXPECT_FALSE(adapter_->IsDiscovering()); // There should be 2 devices BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); EXPECT_EQ(2U, devices.size()); // |devices| are not ordered, verify it contains the 2 device addresses. EXPECT_NE( -1, GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress)); EXPECT_NE( -1, GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedUnconnectableDeviceAddress)); } TEST_F(BluetoothBlueZTest, BecomePresent) { fake_bluetooth_adapter_client_->SetVisible(false); GetAdapter(); ASSERT_FALSE(adapter_->IsPresent()); // Install an observer; expect the AdapterPresentChanged to be called // with true, and IsPresent() to return true. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(true); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_TRUE(observer.last_present()); EXPECT_TRUE(adapter_->IsPresent()); // We should have had a device announced. EXPECT_EQ(2, observer.device_added_count()); EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kPairedUnconnectableDeviceAddress, observer.last_device_address()); // Other callbacks shouldn't be called if the values are false. EXPECT_EQ(0, observer.powered_changed_count()); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(adapter_->IsPowered()); EXPECT_FALSE(adapter_->IsDiscovering()); } TEST_F(BluetoothBlueZTest, BecomeNotPresent) { GetAdapter(); ASSERT_TRUE(adapter_->IsPresent()); // Install an observer; expect the AdapterPresentChanged to be called // with false, and IsPresent() to return false. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); // We should have had 2 devices removed. EXPECT_EQ(2, observer.device_removed_count()); // 2 possibilities for the last device here. std::string address = observer.last_device_address(); EXPECT_TRUE(address.compare(bluez::FakeBluetoothDeviceClient:: kPairedUnconnectableDeviceAddress) == 0 || address.compare( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress) == 0); // Other callbacks shouldn't be called since the values are false. EXPECT_EQ(0, observer.powered_changed_count()); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(adapter_->IsPowered()); EXPECT_FALSE(adapter_->IsDiscovering()); } TEST_F(BluetoothBlueZTest, SecondAdapter) { GetAdapter(); ASSERT_TRUE(adapter_->IsPresent()); // Install an observer, then add a second adapter. Nothing should change, // we ignore the second adapter. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetSecondVisible(true); EXPECT_EQ(0, observer.present_changed_count()); EXPECT_TRUE(adapter_->IsPresent()); EXPECT_EQ(bluez::FakeBluetoothAdapterClient::kAdapterAddress, adapter_->GetAddress()); // Try removing the first adapter, we should now act as if the adapter // is no longer present rather than fall back to the second. fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); // We should have had 2 devices removed. EXPECT_EQ(2, observer.device_removed_count()); // As BluetoothAdapter devices removal does not keep the order of adding them, // 2 possibilities for the last device here. std::string address = observer.last_device_address(); EXPECT_TRUE(address.compare(bluez::FakeBluetoothDeviceClient:: kPairedUnconnectableDeviceAddress) == 0 || address.compare( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress) == 0); // Other callbacks shouldn't be called since the values are false. EXPECT_EQ(0, observer.powered_changed_count()); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(adapter_->IsPowered()); EXPECT_FALSE(adapter_->IsDiscovering()); observer.Reset(); // Removing the second adapter shouldn't set anything either. fake_bluetooth_adapter_client_->SetSecondVisible(false); EXPECT_EQ(0, observer.device_removed_count()); EXPECT_EQ(0, observer.powered_changed_count()); EXPECT_EQ(0, observer.discovering_changed_count()); } TEST_F(BluetoothBlueZTest, BecomePowered) { GetAdapter(); ASSERT_FALSE(adapter_->IsPowered()); // Install an observer; expect the AdapterPoweredChanged to be called // with true, and IsPowered() to return true. TestBluetoothAdapterObserver observer(adapter_); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.powered_changed_count()); EXPECT_TRUE(observer.last_powered()); EXPECT_TRUE(adapter_->IsPowered()); } TEST_F(BluetoothBlueZTest, BecomeNotPowered) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); // Install an observer; expect the AdapterPoweredChanged to be called // with false, and IsPowered() to return false. TestBluetoothAdapterObserver observer(adapter_); adapter_->SetPowered(false, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.powered_changed_count()); EXPECT_FALSE(observer.last_powered()); EXPECT_FALSE(adapter_->IsPowered()); } TEST_F(BluetoothBlueZTest, SetPoweredWhenNotPresent) { GetAdapter(); ASSERT_TRUE(adapter_->IsPresent()); // Install an observer; expect the AdapterPresentChanged to be called // with false, and IsPresent() to return false. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); EXPECT_FALSE(adapter_->IsPowered()); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(0, observer.powered_changed_count()); EXPECT_FALSE(observer.last_powered()); EXPECT_FALSE(adapter_->IsPowered()); } TEST_F(BluetoothBlueZTest, ChangeAdapterName) { GetAdapter(); static const std::string new_name(".__."); adapter_->SetName(new_name, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(new_name, adapter_->GetName()); } TEST_F(BluetoothBlueZTest, ChangeAdapterNameWhenNotPresent) { GetAdapter(); ASSERT_TRUE(adapter_->IsPresent()); // Install an observer; expect the AdapterPresentChanged to be called // with false, and IsPresent() to return false. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); EXPECT_FALSE(adapter_->IsPowered()); adapter_->SetName("^o^", GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ("", adapter_->GetName()); } TEST_F(BluetoothBlueZTest, BecomeDiscoverable) { GetAdapter(); ASSERT_FALSE(adapter_->IsDiscoverable()); // Install an observer; expect the AdapterDiscoverableChanged to be called // with true, and IsDiscoverable() to return true. TestBluetoothAdapterObserver observer(adapter_); adapter_->SetDiscoverable(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.discoverable_changed_count()); EXPECT_TRUE(adapter_->IsDiscoverable()); } TEST_F(BluetoothBlueZTest, BecomeNotDiscoverable) { GetAdapter(); adapter_->SetDiscoverable(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsDiscoverable()); // Install an observer; expect the AdapterDiscoverableChanged to be called // with false, and IsDiscoverable() to return false. TestBluetoothAdapterObserver observer(adapter_); adapter_->SetDiscoverable(false, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.discoverable_changed_count()); EXPECT_FALSE(adapter_->IsDiscoverable()); } TEST_F(BluetoothBlueZTest, SetDiscoverableWhenNotPresent) { GetAdapter(); ASSERT_TRUE(adapter_->IsPresent()); ASSERT_FALSE(adapter_->IsDiscoverable()); // Install an observer; expect the AdapterDiscoverableChanged to be called // with true, and IsDiscoverable() to return true. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); EXPECT_FALSE(adapter_->IsDiscoverable()); adapter_->SetDiscoverable(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(0, observer.discoverable_changed_count()); EXPECT_FALSE(adapter_->IsDiscoverable()); } TEST_F(BluetoothBlueZTest, StopDiscovery) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); // Install an observer; aside from the callback, expect the // AdapterDiscoveringChanged method to be called and no longer to be // discovering, TestBluetoothAdapterObserver observer(adapter_); discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); discovery_sessions_.clear(); callback_count_ = 0; // Test that the Stop callbacks get called even if the // BluetoothDiscoverySession objects gets deleted adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); discovery_sessions_.clear(); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } TEST_F(BluetoothBlueZTest, Discovery) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); // First two devices to appear. message_loop_.Run(); EXPECT_EQ(2, observer.device_added_count()); EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress, observer.last_device_address()); // Next we should get another two devices... message_loop_.Run(); EXPECT_EQ(4, observer.device_added_count()); // Okay, let's run forward until a device is actually removed... while (!observer.device_removed_count()) message_loop_.Run(); EXPECT_EQ(1, observer.device_removed_count()); EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kVanishingDeviceAddress, observer.last_device_address()); } TEST_F(BluetoothBlueZTest, PoweredAndDiscovering) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); // Stop the timers that the simulation uses fake_bluetooth_device_client_->EndDiscoverySimulation( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); fake_bluetooth_adapter_client_->SetVisible(false); ASSERT_FALSE(adapter_->IsPresent()); ASSERT_FALSE(discovery_sessions_[0]->IsActive()); // Install an observer; expect the AdapterPresentChanged, // AdapterPoweredChanged and AdapterDiscoveringChanged methods to be called // with true, and IsPresent(), IsPowered() and IsDiscovering() to all // return true. TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_adapter_client_->SetVisible(true); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_TRUE(observer.last_present()); EXPECT_TRUE(adapter_->IsPresent()); EXPECT_EQ(1, observer.powered_changed_count()); EXPECT_TRUE(observer.last_powered()); EXPECT_TRUE(adapter_->IsPowered()); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); observer.Reset(); // Now mark the adapter not present again. Expect the methods to be called // again, to reset the properties back to false fake_bluetooth_adapter_client_->SetVisible(false); EXPECT_EQ(1, observer.present_changed_count()); EXPECT_FALSE(observer.last_present()); EXPECT_FALSE(adapter_->IsPresent()); EXPECT_EQ(1, observer.powered_changed_count()); EXPECT_FALSE(observer.last_powered()); EXPECT_FALSE(adapter_->IsPowered()); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); } // This unit test asserts that the basic reference counting logic works // correctly for discovery requests done via the BluetoothAdapter. TEST_F(BluetoothBlueZTest, MultipleDiscoverySessions) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // Request device discovery 3 times. for (int i = 0; i < 3; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); // The observer should have received the discovering changed event exactly // once, the success callback should have been called 3 times and the adapter // should be discovering. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); // Request to stop discovery twice. for (int i = 0; i < 2; i++) { discovery_sessions_[i]->Stop(GetCallback(), GetErrorCallback()); } // The observer should have received no additional discovering changed events, // the success callback should have been called 2 times and the adapter should // still be discovering. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(5, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); EXPECT_FALSE(discovery_sessions_[1]->IsActive()); EXPECT_TRUE(discovery_sessions_[2]->IsActive()); // Request device discovery 3 times. for (int i = 0; i < 3; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } // The observer should have received no additional discovering changed events, // the success callback should have been called 3 times and the adapter should // still be discovering. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(8, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)6, discovery_sessions_.size()); // Request to stop discovery 4 times. for (int i = 2; i < 6; i++) { discovery_sessions_[i]->Stop(GetCallback(), GetErrorCallback()); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); // The observer should have received the discovering changed event exactly // once, the success callback should have been called 4 times and the adapter // should no longer be discovering. EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_EQ(12, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // All discovery sessions should be inactive. for (int i = 0; i < 6; i++) EXPECT_FALSE(discovery_sessions_[i]->IsActive()); // Request to stop discovery on of the inactive sessions. discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); // The call should have failed. EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_EQ(12, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); } // This unit test asserts that the reference counting logic works correctly in // the cases when the adapter gets reset and D-Bus calls are made outside of // the BluetoothAdapter. TEST_F(BluetoothBlueZTest, UnexpectedChangesDuringMultipleDiscoverySessions) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // Request device discovery 3 times. for (int i = 0; i < 3; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); // The observer should have received the discovering changed event exactly // once, the success callback should have been called 3 times and the adapter // should be discovering. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); for (int i = 0; i < 3; i++) EXPECT_TRUE(discovery_sessions_[i]->IsActive()); // Stop the timers that the simulation uses fake_bluetooth_device_client_->EndDiscoverySimulation( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); // Stop device discovery behind the adapter. The adapter and the observer // should be notified of the change and the reference count should be reset. // Even though bluez::FakeBluetoothAdapterClient does its own reference // counting and // we called 3 BluetoothAdapter::StartDiscoverySession 3 times, the // bluez::FakeBluetoothAdapterClient's count should be only 1 and a single // call to // bluez::FakeBluetoothAdapterClient::StopDiscovery should work. fake_bluetooth_adapter_client_->StopDiscovery( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_EQ(4, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // All discovery session instances should have been updated. for (int i = 0; i < 3; i++) EXPECT_FALSE(discovery_sessions_[i]->IsActive()); discovery_sessions_.clear(); // It should be possible to successfully start discovery. for (int i = 0; i < 2; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); EXPECT_EQ(3, observer.discovering_changed_count()); EXPECT_EQ(6, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)2, discovery_sessions_.size()); for (int i = 0; i < 2; i++) EXPECT_TRUE(discovery_sessions_[i]->IsActive()); fake_bluetooth_device_client_->EndDiscoverySimulation( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); // Make the adapter disappear and appear. This will make it come back as // discovering. When this happens, the reference count should become and // remain 0 as no new request was made through the BluetoothAdapter. fake_bluetooth_adapter_client_->SetVisible(false); ASSERT_FALSE(adapter_->IsPresent()); EXPECT_EQ(4, observer.discovering_changed_count()); EXPECT_EQ(6, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); for (int i = 0; i < 2; i++) EXPECT_FALSE(discovery_sessions_[i]->IsActive()); discovery_sessions_.clear(); fake_bluetooth_adapter_client_->SetVisible(true); ASSERT_TRUE(adapter_->IsPresent()); EXPECT_EQ(5, observer.discovering_changed_count()); EXPECT_EQ(6, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); // Start and stop discovery. At this point, bluez::FakeBluetoothAdapterClient // has // a reference count that is equal to 1. Pretend that this was done by an // application other than us. Starting and stopping discovery will succeed // but it won't cause the discovery state to change. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); // Run the loop, as there should have been a D-Bus call. EXPECT_EQ(5, observer.discovering_changed_count()); EXPECT_EQ(7, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[0]->IsActive()); discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); message_loop_.Run(); // Run the loop, as there should have been a D-Bus call. EXPECT_EQ(5, observer.discovering_changed_count()); EXPECT_EQ(8, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); discovery_sessions_.clear(); // Start discovery again. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); // Run the loop, as there should have been a D-Bus call. EXPECT_EQ(5, observer.discovering_changed_count()); EXPECT_EQ(9, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[0]->IsActive()); // Stop discovery via D-Bus. The fake client's reference count will drop but // the discovery state won't change since our BluetoothAdapter also just // requested it via D-Bus. fake_bluetooth_adapter_client_->StopDiscovery( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(5, observer.discovering_changed_count()); EXPECT_EQ(10, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); // Now end the discovery session. This should change the adapter's discovery // state. discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(6, observer.discovering_changed_count()); EXPECT_EQ(11, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); } TEST_F(BluetoothBlueZTest, InvalidatedDiscoverySessions) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // Request device discovery 3 times. for (int i = 0; i < 3; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); // The observer should have received the discovering changed event exactly // once, the success callback should have been called 3 times and the adapter // should be discovering. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); for (int i = 0; i < 3; i++) EXPECT_TRUE(discovery_sessions_[i]->IsActive()); // Stop the timers that the simulation uses fake_bluetooth_device_client_->EndDiscoverySimulation( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); // Delete all but one discovery session. discovery_sessions_.pop_back(); discovery_sessions_.pop_back(); ASSERT_EQ((size_t)1, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[0]->IsActive()); EXPECT_TRUE(adapter_->IsDiscovering()); // Stop device discovery behind the adapter. The one active discovery session // should become inactive, but more importantly, we shouldn't run into any // memory errors as the sessions that we explicitly deleted should get // cleaned up. fake_bluetooth_adapter_client_->StopDiscovery( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_EQ(4, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); } TEST_F(BluetoothBlueZTest, QueuedDiscoveryRequests) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); // Request to start discovery. The call should be pending. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); EXPECT_EQ(0, callback_count_); fake_bluetooth_device_client_->EndDiscoverySimulation( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); // The underlying adapter has started discovery, but our call hasn't returned // yet. EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_TRUE(discovery_sessions_.empty()); // Request to start discovery twice. These should get queued and there should // be no change in state. for (int i = 0; i < 2; i++) { adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); } EXPECT_EQ(0, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_TRUE(discovery_sessions_.empty()); // Process the pending call. The queued calls should execute and the discovery // session reference count should increase. message_loop_.Run(); EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); // Verify the reference count by removing sessions 3 times. The last request // should remain pending. for (int i = 0; i < 3; i++) { discovery_sessions_[i]->Stop(GetCallback(), GetErrorCallback()); } EXPECT_EQ(5, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); EXPECT_FALSE(discovery_sessions_[1]->IsActive()); EXPECT_TRUE(discovery_sessions_[2]->IsActive()); // Request to stop the session whose call is pending should fail. discovery_sessions_[2]->Stop(GetCallback(), GetErrorCallback()); EXPECT_EQ(5, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_TRUE(discovery_sessions_[2]->IsActive()); // Request to start should get queued. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); EXPECT_EQ(5, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); // Run the pending request. message_loop_.Run(); EXPECT_EQ(6, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(3, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); EXPECT_FALSE(discovery_sessions_[2]->IsActive()); // The queued request to start discovery should have been issued but is still // pending. Run the loop and verify. message_loop_.Run(); EXPECT_EQ(7, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(3, observer.discovering_changed_count()); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)4, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[3]->IsActive()); } TEST_F(BluetoothBlueZTest, StartDiscoverySession) { GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); EXPECT_EQ(0, observer.discovering_changed_count()); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_TRUE(discovery_sessions_.empty()); // Request a new discovery session. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[0]->IsActive()); // Start another session. A new one should be returned in the callback, which // in turn will destroy the previous session. Adapter should still be // discovering and the reference count should be 1. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)2, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[0]->IsActive()); // Request a new session. adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); EXPECT_TRUE(discovery_sessions_[1]->IsActive()); EXPECT_NE(discovery_sessions_[0], discovery_sessions_[1]); // Stop the previous discovery session. The session should end but discovery // should continue. discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); message_loop_.Run(); EXPECT_EQ(1, observer.discovering_changed_count()); EXPECT_EQ(4, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(observer.last_discovering()); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); EXPECT_TRUE(discovery_sessions_[1]->IsActive()); // Delete the current active session. Discovery should eventually stop. discovery_sessions_.clear(); while (observer.last_discovering()) message_loop_.RunUntilIdle(); EXPECT_EQ(2, observer.discovering_changed_count()); EXPECT_EQ(4, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(observer.last_discovering()); EXPECT_FALSE(adapter_->IsDiscovering()); } TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscovery) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_NE(nullptr, filter); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-60, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); discovery_sessions_[0]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_FALSE(discovery_sessions_[0]->IsActive()); ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), (BluetoothDiscoveryFilter*)nullptr); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryFail) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); callback_count_ = 0; fake_bluetooth_adapter_client_->MakeSetDiscoveryFilterFail(); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(1, error_callback_count_); error_callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)0, discovery_sessions_.size()); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } // This test queues two requests to StartDiscovery with pre set filter. This // should result in SetDiscoveryFilter, then StartDiscovery, and SetDiscovery // DBus calls TEST_F(BluetoothBlueZTest, QueuedSetDiscoveryFilterBeforeStartDiscovery) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); df2->SetRSSI(-65); df2->AddUUID(BluetoothUUID("1002")); scoped_ptr discovery_filter2(df2); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; // Queue two requests to start discovery session with filter. adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter2), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); // Run requests, on DBus level there should be call SetDiscoveryFilter, then // StartDiscovery, then SetDiscoveryFilter again. message_loop_.Run(); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)2, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); ASSERT_TRUE(discovery_sessions_[1]->IsActive()); ASSERT_TRUE(df2->Equals(*discovery_sessions_[1]->GetDiscoveryFilter())); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_NE(nullptr, filter); EXPECT_EQ("auto", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); auto uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1002")); discovery_sessions_[0]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); discovery_sessions_[1]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_FALSE(discovery_sessions_[0]->IsActive()); ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), (BluetoothDiscoveryFilter*)nullptr); ASSERT_FALSE(discovery_sessions_[1]->IsActive()); ASSERT_EQ(discovery_sessions_[1]->GetDiscoveryFilter(), (BluetoothDiscoveryFilter*)nullptr); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } // Call StartFilteredDiscovery twice (2nd time while 1st call is still pending). // Make the first SetDiscoveryFilter fail and the second one succeed. It should // end up with one active discovery session. TEST_F(BluetoothBlueZTest, QueuedSetDiscoveryFilterBeforeStartDiscoveryFail) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); BluetoothDiscoveryFilter* df2 = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); df2->SetRSSI(-65); df2->AddUUID(BluetoothUUID("1002")); scoped_ptr discovery_filter2(df2); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; fake_bluetooth_adapter_client_->MakeSetDiscoveryFilterFail(); // Queue two requests to start discovery session with filter. adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter2), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); // First request to SetDiscoveryFilter should fail, resulting in no session // being created. EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); error_callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)0, discovery_sessions_.size()); message_loop_.Run(); // Second request should succeed EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); ASSERT_TRUE(df2->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_NE(nullptr, filter); EXPECT_EQ("bredr", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); auto uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1002")); discovery_sessions_[0]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_FALSE(discovery_sessions_[0]->IsActive()); ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), (BluetoothDiscoveryFilter*)nullptr); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } TEST_F(BluetoothBlueZTest, SetDiscoveryFilterAfterStartDiscovery) { // Test a simulated discovery session. fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestBluetoothAdapterObserver observer(adapter_); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(adapter_->IsPowered()); ASSERT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_TRUE(discovery_sessions_[0]->IsActive()); EXPECT_EQ(1, observer.discovering_changed_count()); observer.Reset(); auto null_instance = scoped_ptr(); null_instance.reset(); ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), null_instance.get()); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); discovery_sessions_[0]->SetDiscoveryFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_NE(nullptr, filter); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-60, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); discovery_sessions_[0]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); ASSERT_TRUE(adapter_->IsPowered()); ASSERT_FALSE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)1, discovery_sessions_.size()); ASSERT_FALSE(discovery_sessions_[0]->IsActive()); ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), (BluetoothDiscoveryFilter*)nullptr); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } // This unit test asserts that the basic reference counting, and filter merging // works correctly for discovery requests done via the BluetoothAdapter. TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryMultiple) { GetAdapter(); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsPowered()); callback_count_ = 0; TestBluetoothAdapterObserver observer(adapter_); // Request device discovery with pre-set filter 3 times. for (int i = 0; i < 3; i++) { scoped_ptr discovery_filter; if (i == 0) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-85); df->AddUUID(BluetoothUUID("1000")); discovery_filter.reset(df); } else if (i == 1) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1020")); df->AddUUID(BluetoothUUID("1001")); discovery_filter.reset(df); } else if (i == 2) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-65); df->AddUUID(BluetoothUUID("1020")); df->AddUUID(BluetoothUUID("1003")); discovery_filter.reset(df); } adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); if (i == 0) { EXPECT_EQ(1, observer.discovering_changed_count()); observer.Reset(); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-85, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); } else if (i == 1) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-85, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } else if (i == 2) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-85, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } } // the success callback should have been called 3 times and the adapter should // be discovering. EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)3, discovery_sessions_.size()); callback_count_ = 0; // Request to stop discovery twice. for (int i = 0; i < 2; i++) { discovery_sessions_[i]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); if (i == 0) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_EQ(3UL, uuids.size()); EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } else if (i == 1) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_EQ(2UL, uuids.size()); EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_EQ(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } else if (i == 2) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_EQ(0UL, uuids.size()); } } // The success callback should have been called 2 times and the adapter should // still be discovering. EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_FALSE(discovery_sessions_[0]->IsActive()); EXPECT_FALSE(discovery_sessions_[1]->IsActive()); EXPECT_TRUE(discovery_sessions_[2]->IsActive()); callback_count_ = 0; // Request device discovery 3 times. for (int i = 0; i < 3; i++) { scoped_ptr discovery_filter; if (i == 0) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-85); df->AddUUID(BluetoothUUID("1000")); discovery_filter.reset(df); } else if (i == 1) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1020")); df->AddUUID(BluetoothUUID("1001")); discovery_filter.reset(df); } else if (i == 2) { BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-65); df->AddUUID(BluetoothUUID("1020")); df->AddUUID(BluetoothUUID("1003")); discovery_filter.reset(df); } adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); // each result in 1 requests. message_loop_.Run(); if (i == 0) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-85, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } else if (i == 1 || i == 2) { auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-85, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); } } // The success callback should have been called 3 times and the adapter should // still be discovering. EXPECT_EQ(3, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_TRUE(adapter_->IsDiscovering()); ASSERT_EQ((size_t)6, discovery_sessions_.size()); callback_count_ = 0; // Request to stop discovery 4 times. for (int i = 2; i < 6; i++) { discovery_sessions_[i]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); // filter no 2 is same as filter no 5, so removing it shouldn't cause any // filter update if (i != 2 && i != 5) message_loop_.Run(); } // Run only once, as there should have been one D-Bus call. message_loop_.Run(); // The success callback should have been called 4 times and the adapter should // no longer be discovering. EXPECT_EQ(4, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_EQ(1, observer.discovering_changed_count()); // All discovery sessions should be inactive. for (int i = 0; i < 6; i++) EXPECT_FALSE(discovery_sessions_[i]->IsActive()); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ(nullptr, filter); } // This unit test asserts that filter merging logic works correctly for filtered // discovery requests done via the BluetoothAdapter. TEST_F(BluetoothBlueZTest, SetDiscoveryFilterMergingTest) { GetAdapter(); adapter_->SetPowered( true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); BluetoothDiscoveryFilter* df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-15); df->AddUUID(BluetoothUUID("1000")); scoped_ptr discovery_filter(df); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); auto filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-15, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); std::vector uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); df = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_LE); df->SetRSSI(-60); df->AddUUID(BluetoothUUID("1020")); df->AddUUID(BluetoothUUID("1001")); discovery_filter = scoped_ptr(df); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("le", *filter->transport); EXPECT_EQ(-60, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter( BluetoothDiscoveryFilter::Transport::TRANSPORT_CLASSIC); df3->SetRSSI(-65); df3->AddUUID(BluetoothUUID("1020")); df3->AddUUID(BluetoothUUID("1003")); scoped_ptr discovery_filter3(df3); adapter_->StartDiscoverySessionWithFilter( std::move(discovery_filter3), base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("auto", *filter->transport); EXPECT_EQ(-65, *filter->rssi); EXPECT_EQ(nullptr, filter->pathloss.get()); uuids = *filter->uuids; EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1000")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1001")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1003")); EXPECT_NE(uuids.end(), std::find(uuids.begin(), uuids.end(), "1020")); // start additionally classic scan adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); message_loop_.Run(); filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); EXPECT_EQ("auto", *filter->transport); EXPECT_EQ(nullptr, filter->rssi.get()); EXPECT_EQ(nullptr, filter->pathloss.get()); EXPECT_EQ(nullptr, filter->uuids.get()); // Request to stop discovery 4 times. for (int i = 3; i >= 0; i--) { discovery_sessions_[i]->Stop( base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); // Every session stopping would trigger filter update message_loop_.Run(); } } TEST_F(BluetoothBlueZTest, DeviceProperties) { GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress, devices[idx]->GetAddress()); // Verify the other device properties. EXPECT_EQ( base::UTF8ToUTF16(bluez::FakeBluetoothDeviceClient::kPairedDeviceName), devices[idx]->GetName()); EXPECT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType()); EXPECT_TRUE(devices[idx]->IsPaired()); EXPECT_FALSE(devices[idx]->IsConnected()); EXPECT_FALSE(devices[idx]->IsConnecting()); // Non HID devices are always connectable. EXPECT_TRUE(devices[idx]->IsConnectable()); BluetoothDevice::UUIDList uuids = devices[idx]->GetUUIDs(); ASSERT_EQ(2U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1800")); EXPECT_EQ(uuids[1], BluetoothUUID("1801")); EXPECT_EQ(BluetoothDevice::VENDOR_ID_USB, devices[idx]->GetVendorIDSource()); EXPECT_EQ(0x05ac, devices[idx]->GetVendorID()); EXPECT_EQ(0x030d, devices[idx]->GetProductID()); EXPECT_EQ(0x0306, devices[idx]->GetDeviceID()); } TEST_F(BluetoothBlueZTest, DeviceClassChanged) { // Simulate a change of class of a device, as sometimes occurs // during discovery. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType()); // Install an observer; expect the DeviceChanged method to be called when // we change the class of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); properties->bluetooth_class.ReplaceValue(0x002580); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(BluetoothDevice::DEVICE_MOUSE, devices[idx]->GetDeviceType()); } TEST_F(BluetoothBlueZTest, DeviceAppearance) { // Simulate a device with appearance. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType()); // Install an observer; expect the DeviceChanged method to be called when // we change the appearance of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); // Let the device come without bluetooth_class. properties->appearance.ReplaceValue(0); // DeviceChanged method called EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); // Set the device appearance as keyboard (961). properties->appearance.ReplaceValue(961); // DeviceChanged method called properties->appearance.set_valid(true); EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(961, devices[idx]->GetAppearance()); // When discovery is over, the value should be invalidated. properties->appearance.set_valid(false); // DeviceChanged method called by NotifyPropertyChanged() properties->NotifyPropertyChanged(properties->appearance.name()); EXPECT_EQ(3, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ((int) BluetoothDevice::kAppearanceNotPresent, devices[idx]->GetAppearance()); // Change the device appearance to mouse (962). properties->appearance.ReplaceValue(962); // DeviceChanged method called properties->appearance.set_valid(true); EXPECT_EQ(4, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(962, devices[idx]->GetAppearance()); // When discovery is over, the value should be invalidated. properties->appearance.set_valid(false); // DeviceChanged method called by NotifyPropertyChanged() properties->NotifyPropertyChanged(properties->appearance.name()); EXPECT_EQ(5, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ((int) BluetoothDevice::kAppearanceNotPresent, devices[idx]->GetAppearance()); } TEST_F(BluetoothBlueZTest, DeviceTypebyAppearanceNotBluetoothClass) { // Test device type of a device with appearance but without bluetooth class. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType()); // Install an observer; expect the DeviceChanged method to be called when // we change the appearance of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); // Let the device come without bluetooth_class. properties->bluetooth_class.ReplaceValue(0); // DeviceChanged method called properties->appearance.ReplaceValue(0); // DeviceChanged method called EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType()); EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); // Set the device appearance as keyboard. properties->appearance.ReplaceValue(961); // DeviceChanged method called properties->appearance.set_valid(true); EXPECT_EQ(BluetoothDevice::DEVICE_KEYBOARD, devices[idx]->GetDeviceType()); EXPECT_EQ(3, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); // When discovery is over, the value should be invalidated. properties->appearance.set_valid(false); // DeviceChanged method called by NotifyPropertyChanged() properties->NotifyPropertyChanged(properties->appearance.name()); EXPECT_EQ(4, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType()); // Change the device appearance to mouse. properties->appearance.ReplaceValue(962); // DeviceChanged method called properties->appearance.set_valid(true); EXPECT_EQ(BluetoothDevice::DEVICE_MOUSE, devices[idx]->GetDeviceType()); EXPECT_EQ(5, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); // When discovery is over, the value should be invalidated. properties->appearance.set_valid(false); // DeviceChanged method called by NotifyPropertyChanged() properties->NotifyPropertyChanged(properties->appearance.name()); EXPECT_EQ(6, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType()); } TEST_F(BluetoothBlueZTest, DeviceNameChanged) { // Simulate a change of name of a device. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress, devices[idx]->GetAddress()); ASSERT_EQ( base::UTF8ToUTF16(bluez::FakeBluetoothDeviceClient::kPairedDeviceName), devices[idx]->GetName()); // Install an observer; expect the DeviceChanged method to be called when // we change the alias of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); static const std::string new_name("New Device Name"); properties->alias.ReplaceValue(new_name); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(base::UTF8ToUTF16(new_name), devices[idx]->GetName()); } TEST_F(BluetoothBlueZTest, DeviceAddressChanged) { // Simulate a change of address of a device. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress, devices[idx]->GetAddress()); ASSERT_EQ( base::UTF8ToUTF16(bluez::FakeBluetoothDeviceClient::kPairedDeviceName), devices[idx]->GetName()); // Install an observer; expect the DeviceAddressChanged method to be called // when we change the alias of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); static const char* kNewAddress = "D9:1F:FC:11:22:33"; properties->address.ReplaceValue(kNewAddress); EXPECT_EQ(1, observer.device_address_changed_count()); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); EXPECT_EQ(std::string(kNewAddress), devices[idx]->GetAddress()); } TEST_F(BluetoothBlueZTest, DeviceUuidsChanged) { // Simulate a change of advertised services of a device. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress, devices[idx]->GetAddress()); BluetoothDevice::UUIDList uuids = devices[idx]->GetUUIDs(); ASSERT_EQ(2U, uuids.size()); ASSERT_EQ(uuids[0], BluetoothUUID("1800")); ASSERT_EQ(uuids[1], BluetoothUUID("1801")); // Install an observer; expect the DeviceChanged method to be called when // we change the class of the device. TestBluetoothAdapterObserver observer(adapter_); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); std::vector new_uuids; new_uuids.push_back(uuids[0].canonical_value()); new_uuids.push_back(uuids[1].canonical_value()); new_uuids.push_back("0000110c-0000-1000-8000-00805f9b34fb"); new_uuids.push_back("0000110e-0000-1000-8000-00805f9b34fb"); new_uuids.push_back("0000110a-0000-1000-8000-00805f9b34fb"); properties->uuids.ReplaceValue(new_uuids); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); // Fetching the value should give the new one. uuids = devices[idx]->GetUUIDs(); ASSERT_EQ(5U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1800")); EXPECT_EQ(uuids[1], BluetoothUUID("1801")); EXPECT_EQ(uuids[2], BluetoothUUID("110c")); EXPECT_EQ(uuids[3], BluetoothUUID("110e")); EXPECT_EQ(uuids[4], BluetoothUUID("110a")); } TEST_F(BluetoothBlueZTest, DeviceInquiryRSSIInvalidated) { // Simulate invalidation of inquiry RSSI of a device, as it occurs // when discovery is finished. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); // During discovery, rssi is a valid value (-75) properties->rssi.ReplaceValue(-75); properties->rssi.set_valid(true); ASSERT_EQ(-75, devices[idx]->GetInquiryRSSI()); // Install an observer; expect the DeviceChanged method to be called when // we invalidate the RSSI of the device. TestBluetoothAdapterObserver observer(adapter_); // When discovery is over, the value should be invalidated. properties->rssi.set_valid(false); properties->NotifyPropertyChanged(properties->rssi.name()); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); int unknown_power = BluetoothDevice::kUnknownPower; EXPECT_EQ(unknown_power, devices[idx]->GetInquiryRSSI()); } TEST_F(BluetoothBlueZTest, DeviceInquiryTxPowerInvalidated) { // Simulate invalidation of inquiry TxPower of a device, as it occurs // when discovery is finished. GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); // During discovery, tx_power is a valid value (0) properties->tx_power.ReplaceValue(0); properties->tx_power.set_valid(true); ASSERT_EQ(0, devices[idx]->GetInquiryTxPower()); // Install an observer; expect the DeviceChanged method to be called when // we invalidate the tx_power of the device. TestBluetoothAdapterObserver observer(adapter_); // When discovery is over, the value should be invalidated. properties->tx_power.set_valid(false); properties->NotifyPropertyChanged(properties->tx_power.name()); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); int unknown_power = BluetoothDevice::kUnknownPower; EXPECT_EQ(unknown_power, devices[idx]->GetInquiryTxPower()); } TEST_F(BluetoothBlueZTest, ForgetDevice) { GetAdapter(); BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); ASSERT_EQ(2U, devices.size()); int idx = GetDeviceIndexByAddress( devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_NE(-1, idx); ASSERT_EQ(bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress, devices[idx]->GetAddress()); std::string address = devices[idx]->GetAddress(); // Install an observer; expect the DeviceRemoved method to be called // with the device we remove. TestBluetoothAdapterObserver observer(adapter_); devices[idx]->Forget(base::Bind(&base::DoNothing), GetErrorCallback()); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.device_removed_count()); EXPECT_EQ(address, observer.last_device_address()); // GetDevices shouldn't return the device either. devices = adapter_->GetDevices(); ASSERT_EQ(1U, devices.size()); } TEST_F(BluetoothBlueZTest, ForgetUnpairedDevice) { GetAdapter(); DiscoverDevices(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConnectUnpairableAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); // Connect the device so it becomes trusted and remembered. device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); ASSERT_EQ(1, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(device->IsConnected()); ASSERT_FALSE(device->IsConnecting()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kConnectUnpairablePath)); ASSERT_TRUE(properties->trusted.value()); // Install an observer; expect the DeviceRemoved method to be called // with the device we remove. TestBluetoothAdapterObserver observer(adapter_); device->Forget(base::Bind(&base::DoNothing), GetErrorCallback()); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.device_removed_count()); EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kConnectUnpairableAddress, observer.last_device_address()); // GetDevices shouldn't return the device either. device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConnectUnpairableAddress); EXPECT_FALSE(device != nullptr); } TEST_F(BluetoothBlueZTest, ConnectPairedDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_TRUE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); // Connect without a pairing delegate; since the device is already Paired // this should succeed and the device should become connected. device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one for connected and one for for trusted // after connecting. EXPECT_EQ(4, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); } TEST_F(BluetoothBlueZTest, ConnectUnpairableDevice) { GetAdapter(); DiscoverDevices(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConnectUnpairableAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); // Connect without a pairing delegate; since the device does not require // pairing, this should succeed and the device should become connected. device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one for connected, one for for trusted after // connection, and one for the reconnect mode (IsConnectable). EXPECT_EQ(5, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kConnectUnpairablePath)); EXPECT_TRUE(properties->trusted.value()); // Verify is a HID device and is not connectable. BluetoothDevice::UUIDList uuids = device->GetUUIDs(); ASSERT_EQ(1U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1124")); EXPECT_FALSE(device->IsConnectable()); } TEST_F(BluetoothBlueZTest, ConnectConnectedDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_TRUE(device->IsPaired()); device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); ASSERT_EQ(1, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(device->IsConnected()); // Connect again; since the device is already Connected, this shouldn't do // anything to initiate the connection. TestBluetoothAdapterObserver observer(adapter_); device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // The observer will be called because Connecting will toggle true and false, // and the trusted property will be updated to true. EXPECT_EQ(3, observer.device_changed_count()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); } TEST_F(BluetoothBlueZTest, ConnectDeviceFails) { GetAdapter(); DiscoverDevices(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kLegacyAutopairAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); // Connect without a pairing delegate; since the device requires pairing, // this should fail with an error. device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_FAILED, last_connect_error_); EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); } TEST_F(BluetoothBlueZTest, DisconnectDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_TRUE(device->IsPaired()); device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); ASSERT_EQ(1, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; ASSERT_TRUE(device->IsConnected()); ASSERT_FALSE(device->IsConnecting()); // Disconnect the device, we should see the observer method fire and the // device get dropped. TestBluetoothAdapterObserver observer(adapter_); device->Disconnect(GetCallback(), GetErrorCallback()); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_FALSE(device->IsConnected()); } TEST_F(BluetoothBlueZTest, DisconnectUnconnectedDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_TRUE(device->IsPaired()); ASSERT_FALSE(device->IsConnected()); // Disconnect the device, we should see the observer method fire and the // device get dropped. TestBluetoothAdapterObserver observer(adapter_); device->Disconnect(GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); } TEST_F(BluetoothBlueZTest, PairTrustedDevice) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient:: kConnectedTrustedNotPairedDevicePath)); BluetoothDevice* device = adapter_->GetDevice(bluez::FakeBluetoothDeviceClient:: kConnectedTrustedNotPairedDeviceAddress); ASSERT_TRUE(device != nullptr); // On the DBus level the device is trusted but not paired. But the current // implementation of |BluetoothDevice::IsPaired()| returns true in this case. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient:: kConnectedTrustedNotPairedDevicePath)); EXPECT_FALSE(properties->paired.value()); EXPECT_TRUE(properties->trusted.value()); ASSERT_TRUE(device->IsPaired()); // The |kConnectedTrustedNotPairedDevicePath| requests a passkey confirmation. // Obs.: This is the flow when CrOS triggers pairing with a iOS device. TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); device->Pair(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_); EXPECT_EQ(123456U, pairing_delegate.last_passkey_); // Confirm the passkey. device->ConfirmPairing(); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Make sure the paired property has been set to true. properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kConnectedTrustedNotPairedDevicePath)); EXPECT_TRUE(properties->paired.value()); } TEST_F(BluetoothBlueZTest, PairAlreadyPairedDevice) { GetAdapter(); fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); ASSERT_TRUE(device != nullptr); // On the DBus level a device can be trusted but not paired. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); EXPECT_TRUE(properties->paired.value()); EXPECT_TRUE(properties->trusted.value()); ASSERT_TRUE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); device->Pair(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); // For already paired devices a call to |Pair| should succeed without calling // the pairing delegate. EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } TEST_F(BluetoothBlueZTest, PairLegacyAutopair) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // The Legacy Autopair device requires no PIN or Passkey to pair because // the daemon provides 0000 to the device for us. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kLegacyAutopairAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_TRUE(device->IsConnecting()); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired, // two for trusted (after pairing and connection), and one for the reconnect // mode (IsConnectable). EXPECT_EQ(7, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Verify is a HID device and is connectable. BluetoothDevice::UUIDList uuids = device->GetUUIDs(); ASSERT_EQ(1U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1124")); EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kLegacyAutopairPath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairDisplayPinCode) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Requires that we display a randomly generated PIN on the screen. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kDisplayPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.display_pincode_count_); EXPECT_EQ("123456", pairing_delegate.last_pincode_); EXPECT_TRUE(device->IsConnecting()); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired, // two for trusted (after pairing and connection), and one for the reconnect // mode (IsConnectable). EXPECT_EQ(7, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Verify is a HID device and is connectable. BluetoothDevice::UUIDList uuids = device->GetUUIDs(); ASSERT_EQ(1U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1124")); EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kDisplayPinCodePath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairDisplayPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Requires that we display a randomly generated Passkey on the screen, // and notifies us as it's typed in. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kDisplayPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); // One call for DisplayPasskey() and one for KeysEntered(). EXPECT_EQ(2, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.display_passkey_count_); EXPECT_EQ(123456U, pairing_delegate.last_passkey_); EXPECT_EQ(1, pairing_delegate.keys_entered_count_); EXPECT_EQ(0U, pairing_delegate.last_entered_); EXPECT_TRUE(device->IsConnecting()); // One call to KeysEntered() for each key, including [enter]. for (int i = 1; i <= 7; ++i) { message_loop_.Run(); EXPECT_EQ(2 + i, pairing_delegate.call_count_); EXPECT_EQ(1 + i, pairing_delegate.keys_entered_count_); EXPECT_EQ(static_cast(i), pairing_delegate.last_entered_); } message_loop_.Run(); // 8 KeysEntered notifications (0 to 7, inclusive) and one aditional call for // DisplayPasskey(). EXPECT_EQ(9, pairing_delegate.call_count_); EXPECT_EQ(8, pairing_delegate.keys_entered_count_); EXPECT_EQ(7U, pairing_delegate.last_entered_); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired, // two for trusted (after pairing and connection), and one for the reconnect // mode (IsConnectable). EXPECT_EQ(7, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Verify is a HID device. BluetoothDevice::UUIDList uuids = device->GetUUIDs(); ASSERT_EQ(1U, uuids.size()); EXPECT_EQ(uuids[0], BluetoothUUID("1124")); // And usually not connectable. EXPECT_FALSE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kDisplayPasskeyPath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairRequestPinCode) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Requires that the user enters a PIN for them. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_pincode_count_); EXPECT_TRUE(device->IsConnecting()); // Set the PIN. device->SetPinCode("1234"); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired and // two for trusted (after pairing and connection). EXPECT_EQ(6, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Verify is not a HID device. BluetoothDevice::UUIDList uuids = device->GetUUIDs(); ASSERT_EQ(0U, uuids.size()); // Non HID devices are always connectable. EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kRequestPinCodePath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairConfirmPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Requests that we confirm a displayed passkey. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_); EXPECT_EQ(123456U, pairing_delegate.last_passkey_); EXPECT_TRUE(device->IsConnecting()); // Confirm the passkey. device->ConfirmPairing(); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired and // two for trusted (after pairing and connection). EXPECT_EQ(6, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Non HID devices are always connectable. EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairRequestPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Requires that the user enters a Passkey, this would be some kind of // device that has a display, but doesn't use "just works" - maybe a car? BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_passkey_count_); EXPECT_TRUE(device->IsConnecting()); // Set the Passkey. device->SetPasskey(1234); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired and // two for trusted (after pairing and connection). EXPECT_EQ(6, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Non HID devices are always connectable. EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairJustWorks) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Uses just-works pairing, since this is an outgoing pairing, no delegate // interaction is required. BluetoothDevice* device = adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kJustWorksAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // Two changes for connecting, one change for connected, one for paired and // two for trusted (after pairing and connection). EXPECT_EQ(6, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Non HID devices are always connectable. EXPECT_TRUE(device->IsConnectable()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairUnpairableDeviceFails) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevice(bluez::FakeBluetoothDeviceClient::kUnconnectableDeviceAddress); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kUnpairableDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_TRUE(device->IsConnecting()); // Run the loop to get the error.. message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_FAILED, last_connect_error_); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingFails) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevice(bluez::FakeBluetoothDeviceClient::kVanishingDeviceAddress); // The vanishing device times out during pairing BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kVanishingDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_TRUE(device->IsConnecting()); // Run the loop to get the error.. message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_TIMEOUT, last_connect_error_); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingFailsAtConnection) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Everything seems to go according to plan with the unconnectable device; // it pairs, but then you can't make connections to it after. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kUnconnectableDeviceAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_TRUE(device->IsConnecting()); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_FAILED, last_connect_error_); // Two changes for connecting, one for paired and one for trusted after // pairing. The device should not be connected. EXPECT_EQ(4, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_TRUE(device->IsPaired()); // Make sure the trusted property has been set to true still (since pairing // worked). bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kUnconnectableDevicePath)); EXPECT_TRUE(properties->trusted.value()); } TEST_F(BluetoothBlueZTest, PairingRejectedAtPinCode) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Reject the pairing after we receive a request for the PIN code. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_pincode_count_); EXPECT_TRUE(device->IsConnecting()); // Reject the pairing. device->RejectPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_REJECTED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingCancelledAtPinCode) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Cancel the pairing after we receive a request for the PIN code. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_pincode_count_); EXPECT_TRUE(device->IsConnecting()); // Cancel the pairing. device->CancelPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_CANCELED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingRejectedAtPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Reject the pairing after we receive a request for the passkey. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_passkey_count_); EXPECT_TRUE(device->IsConnecting()); // Reject the pairing. device->RejectPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_REJECTED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingCancelledAtPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Cancel the pairing after we receive a request for the passkey. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_passkey_count_); EXPECT_TRUE(device->IsConnecting()); // Cancel the pairing. device->CancelPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_CANCELED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingRejectedAtConfirmation) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Reject the pairing after we receive a request for passkey confirmation. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_); EXPECT_TRUE(device->IsConnecting()); // Reject the pairing. device->RejectPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_REJECTED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingCancelledAtConfirmation) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Cancel the pairing after we receive a request for the passkey. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_); EXPECT_TRUE(device->IsConnecting()); // Cancel the pairing. device->CancelPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_CANCELED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, PairingCancelledInFlight) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); DiscoverDevices(); // Cancel the pairing while we're waiting for the remote host. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kLegacyAutopairAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); TestPairingDelegate pairing_delegate; device->Connect(&pairing_delegate, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_EQ(0, pairing_delegate.call_count_); EXPECT_TRUE(device->IsConnecting()); // Cancel the pairing. device->CancelPairing(); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(BluetoothDevice::ERROR_AUTH_CANCELED, last_connect_error_); // Should be no changes except connecting going true and false. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_FALSE(device->IsConnected()); EXPECT_FALSE(device->IsConnecting()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, IncomingPairRequestPinCode) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Requires that we provide a PIN code. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPinCodePath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPinCodePath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_pincode_count_); // Set the PIN. device->SetPinCode("1234"); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // One change for paired, and one for trusted. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsPaired()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kRequestPinCodePath)); ASSERT_TRUE(properties->trusted.value()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairConfirmPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Requests that we confirm a displayed passkey. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.confirm_passkey_count_); EXPECT_EQ(123456U, pairing_delegate.last_passkey_); // Confirm the passkey. device->ConfirmPairing(); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // One change for paired, and one for trusted. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsPaired()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath)); ASSERT_TRUE(properties->trusted.value()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairRequestPasskey) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Requests that we provide a Passkey. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_passkey_count_); // Set the Passkey. device->SetPasskey(1234); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // One change for paired, and one for trusted. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsPaired()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath)); ASSERT_TRUE(properties->trusted.value()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairJustWorks) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Uses just-works pairing so, sinec this an incoming pairing, require // authorization from the user. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath)); BluetoothDevice* device = adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kJustWorksAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.authorize_pairing_count_); // Confirm the pairing. device->ConfirmPairing(); message_loop_.Run(); EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); // One change for paired, and one for trusted. EXPECT_EQ(2, observer.device_changed_count()); EXPECT_EQ(device, observer.last_device()); EXPECT_TRUE(device->IsPaired()); // Make sure the trusted property has been set to true. bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath)); ASSERT_TRUE(properties->trusted.value()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairRequestPinCodeWithoutDelegate) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); // Requires that we provide a PIN Code, without a pairing delegate, // that will be rejected. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPinCodePath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPinCodeAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPinCodePath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_); // No changes should be observer. EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsPaired()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairConfirmPasskeyWithoutDelegate) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); // Requests that we confirm a displayed passkey, without a pairing delegate, // that will be rejected. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kConfirmPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kConfirmPasskeyPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_); // No changes should be observer. EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsPaired()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairRequestPasskeyWithoutDelegate) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); // Requests that we provide a displayed passkey, without a pairing delegate, // that will be rejected. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_); // No changes should be observer. EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsPaired()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, IncomingPairJustWorksWithoutDelegate) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); // Uses just-works pairing and thus requires authorization for incoming // pairings, without a pairing delegate, that will be rejected. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath)); BluetoothDevice* device = adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kJustWorksAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kJustWorksPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_); EXPECT_EQ(bluetooth_device::kErrorAuthenticationRejected, last_client_error_); // No changes should be observer. EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsPaired()); // No pairing context should remain on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); } TEST_F(BluetoothBlueZTest, RemovePairingDelegateDuringPairing) { fake_bluetooth_device_client_->SetSimulationIntervalMs(10); GetAdapter(); TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Requests that we provide a Passkey. fake_bluetooth_device_client_->CreateDevice( dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath)); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kRequestPasskeyAddress); ASSERT_TRUE(device != nullptr); ASSERT_FALSE(device->IsPaired()); TestBluetoothAdapterObserver observer(adapter_); fake_bluetooth_device_client_->SimulatePairing( dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kRequestPasskeyPath), true, GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback, base::Unretained(this))); EXPECT_EQ(1, pairing_delegate.call_count_); EXPECT_EQ(1, pairing_delegate.request_passkey_count_); // A pairing context should now be set on the device. BluetoothDeviceBlueZ* device_bluez = static_cast(device); ASSERT_TRUE(device_bluez->GetPairing() != nullptr); // Removing the pairing delegate should remove that pairing context. adapter_->RemovePairingDelegate(&pairing_delegate); EXPECT_TRUE(device_bluez->GetPairing() == nullptr); // Set the Passkey, this should now have no effect since the pairing has // been, in-effect, cancelled device->SetPasskey(1234); EXPECT_EQ(0, callback_count_); EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(0, observer.device_changed_count()); EXPECT_FALSE(device->IsPaired()); } TEST_F(BluetoothBlueZTest, DeviceId) { GetAdapter(); // Use the built-in paired device for this test, grab its Properties // structure so we can adjust the underlying modalias property. BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); bluez::FakeBluetoothDeviceClient::Properties* properties = fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath( bluez::FakeBluetoothDeviceClient::kPairedDevicePath)); ASSERT_TRUE(device != nullptr); ASSERT_TRUE(properties != nullptr); // Valid USB IF-assigned identifier. ASSERT_EQ("usb:v05ACp030Dd0306", properties->modalias.value()); EXPECT_EQ(BluetoothDevice::VENDOR_ID_USB, device->GetVendorIDSource()); EXPECT_EQ(0x05ac, device->GetVendorID()); EXPECT_EQ(0x030d, device->GetProductID()); EXPECT_EQ(0x0306, device->GetDeviceID()); // Valid Bluetooth SIG-assigned identifier. properties->modalias.ReplaceValue("bluetooth:v00E0p2400d0400"); EXPECT_EQ(BluetoothDevice::VENDOR_ID_BLUETOOTH, device->GetVendorIDSource()); EXPECT_EQ(0x00e0, device->GetVendorID()); EXPECT_EQ(0x2400, device->GetProductID()); EXPECT_EQ(0x0400, device->GetDeviceID()); // Invalid USB IF-assigned identifier. properties->modalias.ReplaceValue("usb:x00E0p2400d0400"); EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource()); EXPECT_EQ(0, device->GetVendorID()); EXPECT_EQ(0, device->GetProductID()); EXPECT_EQ(0, device->GetDeviceID()); // Invalid Bluetooth SIG-assigned identifier. properties->modalias.ReplaceValue("bluetooth:x00E0p2400d0400"); EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource()); EXPECT_EQ(0, device->GetVendorID()); EXPECT_EQ(0, device->GetProductID()); EXPECT_EQ(0, device->GetDeviceID()); // Unknown vendor specification identifier. properties->modalias.ReplaceValue("chrome:v00E0p2400d0400"); EXPECT_EQ(BluetoothDevice::VENDOR_ID_UNKNOWN, device->GetVendorIDSource()); EXPECT_EQ(0, device->GetVendorID()); EXPECT_EQ(0, device->GetProductID()); EXPECT_EQ(0, device->GetDeviceID()); } TEST_F(BluetoothBlueZTest, GetConnectionInfoForDisconnectedDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); // Calling GetConnectionInfo for an unconnected device should return a result // in which all fields are filled with BluetoothDevice::kUnknownPower. BluetoothDevice::ConnectionInfo conn_info(0, 0, 0); device->GetConnectionInfo(base::Bind(&SaveConnectionInfo, &conn_info)); int unknown_power = BluetoothDevice::kUnknownPower; EXPECT_NE(0, unknown_power); EXPECT_EQ(unknown_power, conn_info.rssi); EXPECT_EQ(unknown_power, conn_info.transmit_power); EXPECT_EQ(unknown_power, conn_info.max_transmit_power); } TEST_F(BluetoothBlueZTest, GetConnectionInfoForConnectedDevice) { GetAdapter(); BluetoothDevice* device = adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress); device->Connect(nullptr, GetCallback(), base::Bind(&BluetoothBlueZTest::ConnectErrorCallback, base::Unretained(this))); EXPECT_TRUE(device->IsConnected()); // Calling GetConnectionInfo for a connected device should return valid // results. fake_bluetooth_device_client_->UpdateConnectionInfo(-10, 3, 4); BluetoothDevice::ConnectionInfo conn_info; device->GetConnectionInfo(base::Bind(&SaveConnectionInfo, &conn_info)); EXPECT_EQ(-10, conn_info.rssi); EXPECT_EQ(3, conn_info.transmit_power); EXPECT_EQ(4, conn_info.max_transmit_power); } // Verifies Shutdown shuts down the adapter as expected. TEST_F(BluetoothBlueZTest, Shutdown) { // Set up adapter. Set powered & discoverable, start discovery. GetAdapter(); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); adapter_->SetDiscoverable(true, GetCallback(), GetErrorCallback()); adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); base::MessageLoop::current()->Run(); ASSERT_EQ(3, callback_count_); ASSERT_EQ(0, error_callback_count_); callback_count_ = 0; TestPairingDelegate pairing_delegate; adapter_->AddPairingDelegate( &pairing_delegate, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); // Validate running adapter state. EXPECT_NE("", adapter_->GetAddress()); EXPECT_NE("", adapter_->GetName()); EXPECT_TRUE(adapter_->IsInitialized()); EXPECT_TRUE(adapter_->IsPresent()); EXPECT_TRUE(adapter_->IsPowered()); EXPECT_TRUE(adapter_->IsDiscoverable()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_EQ(2U, adapter_->GetDevices().size()); EXPECT_NE(nullptr, adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress)); EXPECT_NE(dbus::ObjectPath(""), static_cast(adapter_.get())->object_path()); // Shutdown adapter_->Shutdown(); // Validate post shutdown state by calling all BluetoothAdapterBlueZ // members, in declaration order: adapter_->Shutdown(); // DeleteOnCorrectThread omitted as we don't want to delete in this test. { TestBluetoothAdapterObserver observer(adapter_); // Calls AddObserver } // ~TestBluetoothAdapterObserver calls RemoveObserver. EXPECT_EQ("", adapter_->GetAddress()); EXPECT_EQ("", adapter_->GetName()); adapter_->SetName("", GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_--) << "SetName error"; EXPECT_TRUE(adapter_->IsInitialized()); EXPECT_FALSE(adapter_->IsPresent()); EXPECT_FALSE(adapter_->IsPowered()); adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_--) << "SetPowered error"; EXPECT_FALSE(adapter_->IsDiscoverable()); adapter_->SetDiscoverable(true, GetCallback(), GetErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_--) << "SetDiscoverable error"; EXPECT_FALSE(adapter_->IsDiscovering()); // CreateRfcommService will DCHECK after Shutdown(). // CreateL2capService will DCHECK after Shutdown(). BluetoothAudioSink::Options audio_sink_options; adapter_->RegisterAudioSink( audio_sink_options, base::Bind(&BluetoothBlueZTest::AudioSinkAcquiredCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::AudioSinkErrorCallback, base::Unretained(this))); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_--) << "RegisterAudioSink error"; BluetoothAdapterBlueZ* adapter_chrome_os = static_cast(adapter_.get()); EXPECT_EQ(nullptr, adapter_chrome_os->GetDeviceWithPath(dbus::ObjectPath(""))); // Notify methods presume objects exist that are owned by the adapter and // destroyed in Shutdown(). Mocks are not attempted here that won't exist, // as verified below by EXPECT_EQ(0U, adapter_->GetDevices().size()); // NotifyDeviceChanged // NotifyGattServiceAdded // NotifyGattServiceRemoved // NotifyGattServiceChanged // NotifyGattDiscoveryComplete // NotifyGattCharacteristicAdded // NotifyGattCharacteristicRemoved // NotifyGattDescriptorAdded // NotifyGattDescriptorRemoved // NotifyGattCharacteristicValueChanged // NotifyGattDescriptorValueChanged EXPECT_EQ(dbus::ObjectPath(""), adapter_chrome_os->object_path()); adapter_profile_ = nullptr; FakeBluetoothProfileServiceProviderDelegate profile_delegate; adapter_chrome_os->UseProfile( BluetoothUUID(), dbus::ObjectPath(""), bluez::BluetoothProfileManagerClient::Options(), &profile_delegate, base::Bind(&BluetoothBlueZTest::ProfileRegisteredCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCompletionCallback, base::Unretained(this))); EXPECT_FALSE(adapter_profile_) << "UseProfile error"; EXPECT_EQ(0, callback_count_) << "UseProfile error"; EXPECT_EQ(1, error_callback_count_--) << "UseProfile error"; // Protected and private methods: adapter_chrome_os->RemovePairingDelegateInternal(&pairing_delegate); // AdapterAdded() invalid post Shutdown because it calls SetAdapter. adapter_chrome_os->AdapterRemoved(dbus::ObjectPath("x")); adapter_chrome_os->AdapterPropertyChanged(dbus::ObjectPath("x"), ""); adapter_chrome_os->DeviceAdded(dbus::ObjectPath("")); adapter_chrome_os->DeviceRemoved(dbus::ObjectPath("")); adapter_chrome_os->DevicePropertyChanged(dbus::ObjectPath(""), ""); adapter_chrome_os->InputPropertyChanged(dbus::ObjectPath(""), ""); // bluez::BluetoothAgentServiceProvider::Delegate omitted, dbus will be // shutdown, // with the exception of Released. adapter_chrome_os->Released(); adapter_chrome_os->OnRegisterAgent(); adapter_chrome_os->OnRegisterAgentError("", ""); adapter_chrome_os->OnRequestDefaultAgent(); adapter_chrome_os->OnRequestDefaultAgentError("", ""); adapter_chrome_os->OnRegisterAudioSink( base::Bind(&BluetoothBlueZTest::AudioSinkAcquiredCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::AudioSinkErrorCallback, base::Unretained(this)), scoped_refptr()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(1, error_callback_count_--) << "RegisterAudioSink error"; // GetPairing will DCHECK after Shutdown(). // SetAdapter will DCHECK after Shutdown(). // SetDefaultAdapterName will DCHECK after Shutdown(). // RemoveAdapter will DCHECK after Shutdown(). adapter_chrome_os->PoweredChanged(false); adapter_chrome_os->DiscoverableChanged(false); adapter_chrome_os->DiscoveringChanged(false); adapter_chrome_os->PresentChanged(false); adapter_chrome_os->OnSetDiscoverable(GetCallback(), GetErrorCallback(), true); EXPECT_EQ(0, callback_count_) << "OnSetDiscoverable error"; EXPECT_EQ(1, error_callback_count_--) << "OnSetDiscoverable error"; adapter_chrome_os->OnPropertyChangeCompleted(GetCallback(), GetErrorCallback(), true); EXPECT_EQ(0, callback_count_) << "OnPropertyChangeCompleted error"; EXPECT_EQ(1, error_callback_count_--) << "OnPropertyChangeCompleted error"; adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); EXPECT_EQ(0, callback_count_) << "AddDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "AddDiscoverySession error"; adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); EXPECT_EQ(0, callback_count_) << "RemoveDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "RemoveDiscoverySession error"; // OnStartDiscovery tested in Shutdown_OnStartDiscovery // OnStartDiscoveryError tested in Shutdown_OnStartDiscoveryError // OnStopDiscovery tested in Shutdown_OnStopDiscovery // OnStopDiscoveryError tested in Shutdown_OnStopDiscoveryError adapter_profile_ = nullptr; // OnRegisterProfile SetProfileDelegate, OnRegisterProfileError, require // UseProfile to be set first, do so again here just before calling them. adapter_chrome_os->UseProfile( BluetoothUUID(), dbus::ObjectPath(""), bluez::BluetoothProfileManagerClient::Options(), &profile_delegate, base::Bind(&BluetoothBlueZTest::ProfileRegisteredCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCompletionCallback, base::Unretained(this))); EXPECT_FALSE(adapter_profile_) << "UseProfile error"; EXPECT_EQ(0, callback_count_) << "UseProfile error"; EXPECT_EQ(1, error_callback_count_--) << "UseProfile error"; adapter_chrome_os->SetProfileDelegate( BluetoothUUID(), dbus::ObjectPath(""), &profile_delegate, base::Bind(&BluetoothBlueZTest::ProfileRegisteredCallback, base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCompletionCallback, base::Unretained(this))); EXPECT_EQ(0, callback_count_) << "SetProfileDelegate error"; EXPECT_EQ(1, error_callback_count_--) << "SetProfileDelegate error"; adapter_chrome_os->OnRegisterProfileError(BluetoothUUID(), "", ""); EXPECT_EQ(0, callback_count_) << "OnRegisterProfileError error"; EXPECT_EQ(0, error_callback_count_) << "OnRegisterProfileError error"; adapter_chrome_os->ProcessQueuedDiscoveryRequests(); // From BluetoothAdapater: adapter_->StartDiscoverySession( base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); EXPECT_EQ(0, callback_count_) << "StartDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "StartDiscoverySession error"; EXPECT_EQ(0U, adapter_->GetDevices().size()); EXPECT_EQ(nullptr, adapter_->GetDevice( bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress)); TestPairingDelegate pairing_delegate2; adapter_->AddPairingDelegate( &pairing_delegate2, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); adapter_->RemovePairingDelegate(&pairing_delegate2); } // Verifies post-Shutdown of discovery sessions and OnStartDiscovery. TEST_F(BluetoothBlueZTest, Shutdown_OnStartDiscovery) { const int kNumberOfDiscoverySessions = 10; GetAdapter(); BluetoothAdapterBlueZ* adapter_chrome_os = static_cast(adapter_.get()); for (int i = 0; i < kNumberOfDiscoverySessions; i++) { adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); EXPECT_EQ(0, callback_count_); EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); } // Verifies post-Shutdown of discovery sessions and OnStartDiscoveryError. TEST_F(BluetoothBlueZTest, Shutdown_OnStartDiscoveryError) { const int kNumberOfDiscoverySessions = 10; GetAdapter(); BluetoothAdapterBlueZ* adapter_chrome_os = static_cast(adapter_.get()); for (int i = 0; i < kNumberOfDiscoverySessions; i++) { adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStartDiscoveryError(GetCallback(), GetDiscoveryErrorCallback(), "", ""); EXPECT_EQ(0, callback_count_); EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); } // Verifies post-Shutdown of discovery sessions and OnStartDiscovery. TEST_F(BluetoothBlueZTest, Shutdown_OnStopDiscovery) { const int kNumberOfDiscoverySessions = 10; GetAdapter(); BluetoothAdapterBlueZ* adapter_chrome_os = static_cast(adapter_.get()); // In order to queue up discovery sessions before an OnStopDiscovery call // RemoveDiscoverySession must be called, so Add, Start, and Remove: adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscovery. for (int i = 0; i < kNumberOfDiscoverySessions; i++) { adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStopDiscovery(GetCallback()); // 1 successful stopped discovery from RemoveDiscoverySession, and // kNumberOfDiscoverySessions errors from AddDiscoverySession/OnStopDiscovery. EXPECT_EQ(1, callback_count_); EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); } // Verifies post-Shutdown of discovery sessions and OnStopDiscoveryError. TEST_F(BluetoothBlueZTest, Shutdown_OnStopDiscoveryError) { const int kNumberOfDiscoverySessions = 10; GetAdapter(); BluetoothAdapterBlueZ* adapter_chrome_os = static_cast(adapter_.get()); // In order to queue up discovery sessions before an OnStopDiscoveryError call // RemoveDiscoverySession must be called, so Add, Start, and Remove: adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); adapter_chrome_os->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); adapter_chrome_os->RemoveDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscoveryError. for (int i = 0; i < kNumberOfDiscoverySessions; i++) { adapter_chrome_os->AddDiscoverySession(nullptr, GetCallback(), GetDiscoveryErrorCallback()); } adapter_->Shutdown(); adapter_chrome_os->OnStopDiscoveryError(GetDiscoveryErrorCallback(), "", ""); // 1 error reported to RemoveDiscoverySession because of OnStopDiscoveryError, // and kNumberOfDiscoverySessions errors queued with AddDiscoverySession. EXPECT_EQ(0, callback_count_); EXPECT_EQ(1 + kNumberOfDiscoverySessions, error_callback_count_); } } // namespace bluez