Commit 614a8f74 authored by James Hawkins's avatar James Hawkins Committed by Commit Bot

Proximity Auth: Remove unused BluetoothLowEnergeyConnectionFinder.

R=khorimoto@chromium.org

Bug: 899324
Test: none
Change-Id: I00093b332711218ac96cca78fdfe17ab8ae7f1e7
Reviewed-on: https://chromium-review.googlesource.com/c/1330720Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Commit-Queue: James Hawkins <jhawkins@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607062}
parent 32758758
...@@ -8,8 +8,6 @@ assert(is_chromeos, "ProximityAuth is Chrome OS only") ...@@ -8,8 +8,6 @@ assert(is_chromeos, "ProximityAuth is Chrome OS only")
static_library("proximity_auth") { static_library("proximity_auth") {
sources = [ sources = [
"bluetooth_low_energy_connection_finder.cc",
"bluetooth_low_energy_connection_finder.h",
"messenger.h", "messenger.h",
"messenger_impl.cc", "messenger_impl.cc",
"messenger_impl.h", "messenger_impl.h",
...@@ -98,7 +96,6 @@ static_library("test_support") { ...@@ -98,7 +96,6 @@ static_library("test_support") {
source_set("unit_tests") { source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"bluetooth_low_energy_connection_finder_unittest.cc",
"messenger_impl_unittest.cc", "messenger_impl_unittest.cc",
"proximity_auth_local_state_pref_manager_unittest.cc", "proximity_auth_local_state_pref_manager_unittest.cc",
"proximity_auth_profile_pref_manager_unittest.cc", "proximity_auth_profile_pref_manager_unittest.cc",
......
// Copyright 2015 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 "chromeos/components/proximity_auth/bluetooth_low_energy_connection_finder.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "components/cryptauth/background_eid_generator.h"
#include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h"
#include "components/cryptauth/connection.h"
#include "components/cryptauth/raw_eid_generator.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_common.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_uuid.h"
using device::BluetoothAdapter;
using device::BluetoothDevice;
using device::BluetoothGattConnection;
using device::BluetoothDiscoveryFilter;
namespace proximity_auth {
namespace {
const char kAdvertisementUUID[] = "0000fe50-0000-1000-8000-00805f9b34fb";
const char kBLEGattServiceUUID[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11";
const int kRestartDiscoveryOnErrorDelaySeconds = 2;
} // namespace
BluetoothLowEnergyConnectionFinder::BluetoothLowEnergyConnectionFinder(
cryptauth::RemoteDeviceRef remote_device)
: BluetoothLowEnergyConnectionFinder(
remote_device,
kBLEGattServiceUUID,
std::make_unique<cryptauth::BackgroundEidGenerator>()) {}
BluetoothLowEnergyConnectionFinder::BluetoothLowEnergyConnectionFinder(
cryptauth::RemoteDeviceRef remote_device,
const std::string& service_uuid,
std::unique_ptr<cryptauth::BackgroundEidGenerator> eid_generator)
: remote_device_(remote_device),
service_uuid_(service_uuid),
eid_generator_(std::move(eid_generator)),
weak_ptr_factory_(this) {}
BluetoothLowEnergyConnectionFinder::~BluetoothLowEnergyConnectionFinder() {
if (discovery_session_) {
StopDiscoverySession();
}
if (connection_) {
connection_->RemoveObserver(this);
connection_.reset();
}
if (adapter_) {
adapter_->RemoveObserver(this);
adapter_ = nullptr;
}
}
void BluetoothLowEnergyConnectionFinder::Find(
const cryptauth::ConnectionFinder::ConnectionCallback&
connection_callback) {
if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) {
PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
return;
}
PA_LOG(VERBOSE) << "Finding connection";
connection_callback_ = connection_callback;
device::BluetoothAdapterFactory::GetAdapter(
base::Bind(&BluetoothLowEnergyConnectionFinder::OnAdapterInitialized,
weak_ptr_factory_.GetWeakPtr()));
}
// It's not necessary to observe |AdapterPresentChanged| too. When |adapter_| is
// present, but not powered, it's not possible to scan for new devices.
void BluetoothLowEnergyConnectionFinder::AdapterPoweredChanged(
BluetoothAdapter* adapter,
bool powered) {
DCHECK_EQ(adapter_.get(), adapter);
PA_LOG(VERBOSE) << "Adapter powered: " << powered;
// Important: do not rely on |adapter->IsDiscoverying()| to verify if there is
// an active discovery session. We need to create our own with an specific
// filter.
if (powered && (!discovery_session_ || !discovery_session_->IsActive()))
StartDiscoverySession();
}
void BluetoothLowEnergyConnectionFinder::DeviceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device) {
DCHECK_EQ(adapter_.get(), adapter);
DCHECK(device);
// Note: Only consider |device| when it was actually added/updated during a
// scanning, otherwise the device is stale and the GATT connection will fail.
// For instance, when |adapter_| change status from unpowered to powered,
// |DeviceAdded| is called for each paired |device|.
if (adapter_->IsPowered() && discovery_session_ &&
discovery_session_->IsActive())
HandleDeviceUpdated(device);
}
void BluetoothLowEnergyConnectionFinder::DeviceChanged(
BluetoothAdapter* adapter,
BluetoothDevice* device) {
DCHECK_EQ(adapter_.get(), adapter);
DCHECK(device);
// Note: Only consider |device| when it was actually added/updated during a
// scanning, otherwise the device is stale and the GATT connection will fail.
// For instance, when |adapter_| change status from unpowered to powered,
// |DeviceAdded| is called for each paired |device|.
if (adapter_->IsPowered() && discovery_session_ &&
discovery_session_->IsActive())
HandleDeviceUpdated(device);
}
void BluetoothLowEnergyConnectionFinder::HandleDeviceUpdated(
BluetoothDevice* device) {
// Ensuring only one call to |CreateConnection()| is made. A new |connection_|
// can be created only when the previous one disconnects, triggering a call to
// |OnConnectionStatusChanged|.
if (connection_)
return;
if (IsRightDevice(device)) {
PA_LOG(VERBOSE) << "Connecting to device " << device->GetAddress();
connection_ = CreateConnection(device);
connection_->AddObserver(this);
connection_->Connect();
StopDiscoverySession();
}
}
bool BluetoothLowEnergyConnectionFinder::IsRightDevice(
BluetoothDevice* device) {
if (!device)
return false;
device::BluetoothUUID advertisement_uuid(kAdvertisementUUID);
const std::vector<uint8_t>* service_data =
device->GetServiceDataForUUID(advertisement_uuid);
if (!service_data)
return false;
std::string service_data_string(service_data->begin(), service_data->end());
std::vector<cryptauth::DataWithTimestamp> nearest_eids =
eid_generator_->GenerateNearestEids(remote_device_.beacon_seeds());
for (const cryptauth::DataWithTimestamp& eid : nearest_eids) {
if (eid.data == service_data_string) {
PA_LOG(VERBOSE) << "Found a matching EID: " << eid.DataInHex();
return true;
}
}
return false;
}
void BluetoothLowEnergyConnectionFinder::OnAdapterInitialized(
scoped_refptr<BluetoothAdapter> adapter) {
PA_LOG(VERBOSE) << "Adapter ready";
adapter_ = adapter;
adapter_->AddObserver(this);
StartDiscoverySession();
}
void BluetoothLowEnergyConnectionFinder::OnDiscoverySessionStarted(
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
PA_LOG(VERBOSE) << "Discovery session started";
discovery_session_ = std::move(discovery_session);
}
void BluetoothLowEnergyConnectionFinder::OnStartDiscoverySessionError() {
PA_LOG(WARNING) << "Error starting discovery session, restarting in "
<< kRestartDiscoveryOnErrorDelaySeconds << " seconds.";
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&BluetoothLowEnergyConnectionFinder::RestartDiscoverySessionAsync,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kRestartDiscoveryOnErrorDelaySeconds));
}
void BluetoothLowEnergyConnectionFinder::StartDiscoverySession() {
DCHECK(adapter_);
if (discovery_session_ && discovery_session_->IsActive()) {
PA_LOG(VERBOSE) << "Discovery session already active";
return;
}
// Discover only low energy (LE) devices.
std::unique_ptr<BluetoothDiscoveryFilter> filter(
new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE));
adapter_->StartDiscoverySessionWithFilter(
std::move(filter),
base::Bind(&BluetoothLowEnergyConnectionFinder::OnDiscoverySessionStarted,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(
&BluetoothLowEnergyConnectionFinder::OnStartDiscoverySessionError,
weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothLowEnergyConnectionFinder::StopDiscoverySession() {
PA_LOG(VERBOSE) << "Stopping discovery session";
// Destroying the discovery session also stops it.
discovery_session_.reset();
}
std::unique_ptr<cryptauth::Connection>
BluetoothLowEnergyConnectionFinder::CreateConnection(
device::BluetoothDevice* bluetooth_device) {
return cryptauth::weave::BluetoothLowEnergyWeaveClientConnection::Factory::
NewInstance(remote_device_, adapter_,
device::BluetoothUUID(service_uuid_), bluetooth_device,
true /* should_set_low_connection_latency */);
}
void BluetoothLowEnergyConnectionFinder::OnConnectionStatusChanged(
cryptauth::Connection* connection,
cryptauth::Connection::Status old_status,
cryptauth::Connection::Status new_status) {
DCHECK_EQ(connection, connection_.get());
PA_LOG(VERBOSE) << "OnConnectionStatusChanged: " << old_status << " -> "
<< new_status;
if (!connection_callback_.is_null() && connection_->IsConnected()) {
adapter_->RemoveObserver(this);
connection_->RemoveObserver(this);
// If we invoke the callback now, the callback function may install its own
// observer to |connection_|. Because we are in the ConnectionObserver
// callstack, this new observer will receive this connection event.
// Therefore, we need to invoke the callback or restart discovery
// asynchronously.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&BluetoothLowEnergyConnectionFinder::InvokeCallbackAsync,
weak_ptr_factory_.GetWeakPtr()));
} else if (old_status == cryptauth::Connection::Status::IN_PROGRESS) {
PA_LOG(WARNING) << "Connection failed. Retrying.";
connection_->RemoveObserver(this);
connection_.reset();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
&BluetoothLowEnergyConnectionFinder::RestartDiscoverySessionAsync,
weak_ptr_factory_.GetWeakPtr()));
}
}
void BluetoothLowEnergyConnectionFinder::RestartDiscoverySessionAsync() {
bool discovery_active = discovery_session_ && discovery_session_->IsActive();
if (!connection_ && !discovery_active) {
PA_LOG(VERBOSE) << "Restarting discovery session.";
StartDiscoverySession();
}
}
void BluetoothLowEnergyConnectionFinder::InvokeCallbackAsync() {
connection_callback_.Run(std::move(connection_));
}
} // namespace proximity_auth
// Copyright 2015 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.
#ifndef CHROMEOS_COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_LOW_ENERGY_CONNECTION_FINDER_H_
#define CHROMEOS_COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_LOW_ENERGY_CONNECTION_FINDER_H_
#include <memory>
#include <set>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "components/cryptauth/background_eid_generator.h"
#include "components/cryptauth/connection.h"
#include "components/cryptauth/connection_finder.h"
#include "components/cryptauth/connection_observer.h"
#include "components/cryptauth/remote_device_ref.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_gatt_connection.h"
namespace proximity_auth {
// This cryptauth::ConnectionFinder implementation is specialized in finding a
// Bluetooth Low Energy remote device. We look for remote devices advertising
// the expected EID for the current or nearby time intervals.
class BluetoothLowEnergyConnectionFinder
: public cryptauth::ConnectionFinder,
public cryptauth::ConnectionObserver,
public device::BluetoothAdapter::Observer {
public:
// Finds (and connects) to a Bluetooth low energy device, based on the EID
// advertised by the remote device.
//
// |remote_device|: The BLE remote device.
BluetoothLowEnergyConnectionFinder(cryptauth::RemoteDeviceRef remote_device);
~BluetoothLowEnergyConnectionFinder() override;
// Finds a connection to the remote device.
void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
connection_callback) override;
// cryptauth::ConnectionObserver:
void OnConnectionStatusChanged(
cryptauth::Connection* connection,
cryptauth::Connection::Status old_status,
cryptauth::Connection::Status new_status) override;
// device::BluetoothAdapter::Observer:
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
void DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
void DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override;
protected:
BluetoothLowEnergyConnectionFinder(
const cryptauth::RemoteDeviceRef remote_device,
const std::string& service_uuid,
std::unique_ptr<cryptauth::BackgroundEidGenerator> eid_generator);
// Creates a proximity_auth::Connection with the device given by
// |device_address|. Exposed for testing.
virtual std::unique_ptr<cryptauth::Connection> CreateConnection(
device::BluetoothDevice* bluetooth_device);
// Checks if |device| is advertising the right EID.
virtual bool IsRightDevice(device::BluetoothDevice* device);
private:
// Callback to be called when the Bluetooth adapter is initialized.
void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
// Checks if |remote_device| contains |remote_service_uuid| and creates a
// connection in that case.
void HandleDeviceUpdated(device::BluetoothDevice* remote_device);
// Callback called when a new discovery session is started.
void OnDiscoverySessionStarted(
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session);
// Callback called when there is an error starting a new discovery session.
void OnStartDiscoverySessionError();
// Starts a discovery session for |adapter_|.
void StartDiscoverySession();
// Stops the discovery session given by |discovery_session_|.
void StopDiscoverySession();
// Restarts the discovery session after creating |connection_| fails.
void RestartDiscoverySessionAsync();
// Used to invoke |connection_callback_| asynchronously, decoupling the
// callback invocation from the ConnectionObserver callstack.
void InvokeCallbackAsync();
// The remote BLE device being searched. It maybe empty, in this case the
// remote device should advertise |remote_service_uuid_| and
// |advertised_name_|.
cryptauth::RemoteDeviceRef remote_device_;
// The UUID of the service used by the Weave socket.
std::string service_uuid_;
// Generates the expected EIDs that may be advertised by |remote_device_|. If
// an EID matches, we know its a device we should connect to.
std::unique_ptr<cryptauth::BackgroundEidGenerator> eid_generator_;
// The Bluetooth adapter over which the Bluetooth connection will be made.
scoped_refptr<device::BluetoothAdapter> adapter_;
// The discovery session associated to this object.
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session_;
// The connection with |remote_device|.
std::unique_ptr<cryptauth::Connection> connection_;
// Callback called when the connection is established.
cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
base::WeakPtrFactory<BluetoothLowEnergyConnectionFinder> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyConnectionFinder);
};
} // namespace proximity_auth
#endif // CHROMEOS_COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_LOW_ENERGY_CONNECTION_FINDER_H_
// Copyright 2015 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 "chromeos/components/proximity_auth/bluetooth_low_energy_connection_finder.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "components/cryptauth/connection.h"
#include "components/cryptauth/fake_connection.h"
#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "components/cryptauth/wire_message.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::AtLeast;
using testing::NiceMock;
using testing::Return;
using testing::StrictMock;
using testing::SaveArg;
using device::BluetoothDevice;
using device::MockBluetoothDevice;
namespace proximity_auth {
namespace {
const char kBLEGattServiceUUID[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11";
const char kAdvertisementUUID[] = "0000fe50-0000-1000-8000-00805f9b34fb";
const int8_t kRssi = -30;
const char kEidForPreviousTimeQuantum[] = "\x12\x34";
const char kEidForCurrentTimeQuantum[] = "\xab\xcd";
const char kEidForNextTimeQuantum[] = "\x56\x78";
const char kWrongEid[] = "\xff\xff";
const int64_t kEidPeriodMs = 60 * 1000 * 15; // 15 minutes.
class MockBluetoothLowEnergyConnectionFinder;
class FakeEidGenerator : public cryptauth::BackgroundEidGenerator {
public:
explicit FakeEidGenerator(
MockBluetoothLowEnergyConnectionFinder* connection_finder)
: connection_finder_(connection_finder) {}
~FakeEidGenerator() override {}
std::vector<cryptauth::DataWithTimestamp> GenerateNearestEids(
const std::vector<cryptauth::BeaconSeed>& beacon_seed) const override;
private:
MockBluetoothLowEnergyConnectionFinder* connection_finder_;
DISALLOW_COPY_AND_ASSIGN(FakeEidGenerator);
};
class MockBluetoothLowEnergyConnectionFinder
: public BluetoothLowEnergyConnectionFinder {
public:
MockBluetoothLowEnergyConnectionFinder()
: BluetoothLowEnergyConnectionFinder(
cryptauth::CreateRemoteDeviceRefForTest(),
kBLEGattServiceUUID,
std::make_unique<FakeEidGenerator>(this)) {}
~MockBluetoothLowEnergyConnectionFinder() override {}
// Mock methods don't support return type std::unique_ptr<>. This is a
// possible workaround: mock a proxy method to be called by the target
// overridden method (CreateConnection).
MOCK_METHOD0(CreateConnectionProxy, cryptauth::Connection*());
// Creates a mock connection and sets an expectation that the mock connection
// finder's CreateConnection() method will be called and will return the
// created connection. Returns a reference to the created connection.
// NOTE: The returned connection's lifetime is managed by the connection
// finder.
cryptauth::FakeConnection* ExpectCreateConnection() {
std::unique_ptr<cryptauth::FakeConnection> connection(
new cryptauth::FakeConnection(
cryptauth::CreateRemoteDeviceRefForTest()));
cryptauth::FakeConnection* connection_alias = connection.get();
EXPECT_CALL(*this, CreateConnectionProxy())
.WillOnce(Return(connection.release()));
return connection_alias;
}
void SetNearestEids(const std::vector<std::string>& eids) {
nearest_eids_ = eids;
}
const std::vector<std::string>& nearest_eids() { return nearest_eids_; }
protected:
std::unique_ptr<cryptauth::Connection> CreateConnection(
device::BluetoothDevice* bluetooth_device) override {
return base::WrapUnique(CreateConnectionProxy());
}
private:
std::vector<std::string> nearest_eids_;
DISALLOW_COPY_AND_ASSIGN(MockBluetoothLowEnergyConnectionFinder);
};
// Not declared in-line due to dependency on
// MockBluetoothLowEnergyConnectionFinder.
std::vector<cryptauth::DataWithTimestamp> FakeEidGenerator::GenerateNearestEids(
const std::vector<cryptauth::BeaconSeed>& beacon_seed) const {
std::vector<std::string> nearest_eids = connection_finder_->nearest_eids();
std::vector<cryptauth::DataWithTimestamp> eid_data_with_timestamps;
int64_t start_of_period_ms = 0;
for (const std::string& eid : nearest_eids) {
eid_data_with_timestamps.push_back(cryptauth::DataWithTimestamp(
eid, start_of_period_ms, start_of_period_ms + kEidPeriodMs));
start_of_period_ms += kEidPeriodMs;
}
return eid_data_with_timestamps;
}
} // namespace
class ProximityAuthBluetoothLowEnergyConnectionFinderTest
: public testing::Test {
protected:
ProximityAuthBluetoothLowEnergyConnectionFinderTest()
: adapter_(new NiceMock<device::MockBluetoothAdapter>),
connection_callback_(
base::Bind(&ProximityAuthBluetoothLowEnergyConnectionFinderTest::
OnConnectionFound,
base::Unretained(this))),
device_(new NiceMock<device::MockBluetoothDevice>(
adapter_.get(),
0,
cryptauth::kTestRemoteDeviceName,
std::string(),
false,
false)),
last_discovery_session_alias_(nullptr) {
device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
std::vector<const device::BluetoothDevice*> devices;
ON_CALL(*adapter_, GetDevices()).WillByDefault(Return(devices));
ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
std::vector<std::string> nearest_eids;
nearest_eids.push_back(kEidForPreviousTimeQuantum);
nearest_eids.push_back(kEidForCurrentTimeQuantum);
nearest_eids.push_back(kEidForNextTimeQuantum);
connection_finder_.SetNearestEids(nearest_eids);
}
void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection) {
last_found_connection_ = std::move(connection);
}
void FindAndExpectStartDiscovery() {
device::BluetoothAdapter::DiscoverySessionCallback discovery_callback;
std::unique_ptr<device::MockBluetoothDiscoverySession> discovery_session(
new NiceMock<device::MockBluetoothDiscoverySession>());
last_discovery_session_alias_ = discovery_session.get();
// Starting a discovery session. StartDiscoveryWithFilterRaw is a proxy for
// StartDiscoveryWithFilter.
EXPECT_CALL(*adapter_, StartDiscoverySessionWithFilterRaw(_, _, _))
.WillOnce(SaveArg<1>(&discovery_callback));
EXPECT_CALL(*adapter_, AddObserver(_));
ON_CALL(*last_discovery_session_alias_, IsActive())
.WillByDefault(Return(true));
connection_finder_.Find(connection_callback_);
ASSERT_FALSE(discovery_callback.is_null());
discovery_callback.Run(std::move(discovery_session));
EXPECT_CALL(*adapter_, RemoveObserver(_)).Times(AtLeast(1));
}
// Prepare |device_| with the given EID.
void PrepareDevice(const std::string& eid) {
PrepareDevice(device_.get(), eid);
}
void PrepareDevice(MockBluetoothDevice* device, const std::string& eid) {
device::BluetoothUUID advertisement_uuid(kAdvertisementUUID);
std::vector<uint8_t> eid_vector(eid.c_str(), eid.c_str() + eid.length());
device::BluetoothDevice::UUIDList uuid_list;
uuid_list.push_back(advertisement_uuid);
device::BluetoothDevice::ServiceDataMap service_data_map;
service_data_map[advertisement_uuid] = eid_vector;
device_->UpdateAdvertisementData(kRssi, base::nullopt /* flags */,
uuid_list, base::nullopt /* tx_power */,
service_data_map,
{} /* manufacturer_data */);
}
scoped_refptr<device::MockBluetoothAdapter> adapter_;
cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
std::unique_ptr<device::MockBluetoothDevice> device_;
std::unique_ptr<cryptauth::Connection> last_found_connection_;
device::MockBluetoothDiscoverySession* last_discovery_session_alias_;
StrictMock<MockBluetoothLowEnergyConnectionFinder> connection_finder_;
private:
base::MessageLoop message_loop_;
};
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_StartsDiscoverySession) {
EXPECT_CALL(*adapter_, StartDiscoverySessionWithFilterRaw(_, _, _));
EXPECT_CALL(*adapter_, AddObserver(_));
connection_finder_.Find(connection_callback_);
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_StopsDiscoverySessionBeforeDestroying) {
device::BluetoothAdapter::DiscoverySessionCallback discovery_callback;
std::unique_ptr<device::MockBluetoothDiscoverySession> discovery_session(
new NiceMock<device::MockBluetoothDiscoverySession>());
device::MockBluetoothDiscoverySession* discovery_session_alias =
discovery_session.get();
EXPECT_CALL(*adapter_, StartDiscoverySessionWithFilterRaw(_, _, _))
.WillOnce(SaveArg<1>(&discovery_callback));
ON_CALL(*discovery_session_alias, IsActive()).WillByDefault(Return(true));
EXPECT_CALL(*adapter_, AddObserver(_));
connection_finder_.Find(connection_callback_);
ASSERT_FALSE(discovery_callback.is_null());
discovery_callback.Run(std::move(discovery_session));
EXPECT_CALL(*adapter_, RemoveObserver(_));
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_DeviceAdded_EidMatches) {
FindAndExpectStartDiscovery();
connection_finder_.ExpectCreateConnection();
PrepareDevice(kEidForCurrentTimeQuantum);
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_DeviceChanged_EidMatches) {
FindAndExpectStartDiscovery();
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
connection_finder_.ExpectCreateConnection();
PrepareDevice(kEidForPreviousTimeQuantum);
connection_finder_.DeviceChanged(adapter_.get(), device_.get());
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_DeviceAdded_EidDoesNotMatch) {
FindAndExpectStartDiscovery();
PrepareDevice(kWrongEid);
EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_DeviceChanged_EidDoesNotMatch) {
FindAndExpectStartDiscovery();
PrepareDevice(kWrongEid);
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
connection_finder_.DeviceChanged(adapter_.get(), device_.get());
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_CreatesOnlyOneConnection) {
FindAndExpectStartDiscovery();
// Prepare first device with valid EID.
PrepareDevice(kEidForCurrentTimeQuantum);
// Prepare second device with valid EID.
NiceMock<device::MockBluetoothDevice> other_device(
adapter_.get(), 0, cryptauth::kTestRemoteDeviceName, std::string(), false,
false);
PrepareDevice(&other_device, kEidForPreviousTimeQuantum);
// Add the devices. Only one connection is expected.
connection_finder_.ExpectCreateConnection();
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
connection_finder_.DeviceAdded(adapter_.get(), &other_device);
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_EidMatches_ConnectionSucceeds) {
// Starting discovery.
FindAndExpectStartDiscovery();
// Finding and creating a connection to the right device.
cryptauth::FakeConnection* connection =
connection_finder_.ExpectCreateConnection();
PrepareDevice(kEidForCurrentTimeQuantum);
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
// Creating a connection.
base::RunLoop run_loop;
EXPECT_FALSE(last_found_connection_);
connection->SetStatus(cryptauth::Connection::Status::IN_PROGRESS);
connection->SetStatus(cryptauth::Connection::Status::CONNECTED);
run_loop.RunUntilIdle();
EXPECT_TRUE(last_found_connection_);
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_ConnectionFails_RestartDiscoveryAndConnectionSucceeds) {
// Starting discovery.
FindAndExpectStartDiscovery();
// Preparing to create a GATT connection to the right device.
PrepareDevice(kEidForNextTimeQuantum);
cryptauth::FakeConnection* connection =
connection_finder_.ExpectCreateConnection();
// Trying to create a connection.
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
ASSERT_FALSE(last_found_connection_);
connection->SetStatus(cryptauth::Connection::Status::IN_PROGRESS);
// Preparing to restart the discovery session.
device::BluetoothAdapter::DiscoverySessionCallback discovery_callback;
std::vector<const device::BluetoothDevice*> devices;
ON_CALL(*adapter_, GetDevices()).WillByDefault(Return(devices));
EXPECT_CALL(*adapter_, StartDiscoverySessionWithFilterRaw(_, _, _))
.WillOnce(SaveArg<1>(&discovery_callback));
// Connection fails.
{
base::RunLoop run_loop;
connection->SetStatus(cryptauth::Connection::Status::DISCONNECTED);
run_loop.RunUntilIdle();
}
// Restarting the discovery session.
std::unique_ptr<device::MockBluetoothDiscoverySession> discovery_session(
new NiceMock<device::MockBluetoothDiscoverySession>());
last_discovery_session_alias_ = discovery_session.get();
ON_CALL(*last_discovery_session_alias_, IsActive())
.WillByDefault(Return(true));
ASSERT_FALSE(discovery_callback.is_null());
discovery_callback.Run(std::move(discovery_session));
// Connect again.
PrepareDevice(kEidForNextTimeQuantum);
connection = connection_finder_.ExpectCreateConnection();
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
// Completing the connection.
{
base::RunLoop run_loop;
EXPECT_FALSE(last_found_connection_);
connection->SetStatus(cryptauth::Connection::Status::IN_PROGRESS);
connection->SetStatus(cryptauth::Connection::Status::CONNECTED);
run_loop.RunUntilIdle();
}
EXPECT_TRUE(last_found_connection_);
}
TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest,
Find_AdapterRemoved_RestartDiscoveryAndConnectionSucceeds) {
// Starting discovery.
FindAndExpectStartDiscovery();
// Removing the adapter.
ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false));
ON_CALL(*last_discovery_session_alias_, IsActive())
.WillByDefault(Return(false));
connection_finder_.AdapterPoweredChanged(adapter_.get(), false);
connection_finder_.AdapterPresentChanged(adapter_.get(), false);
// Adding the adapter.
ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
device::BluetoothAdapter::DiscoverySessionCallback discovery_callback;
std::unique_ptr<device::MockBluetoothDiscoverySession> discovery_session(
new NiceMock<device::MockBluetoothDiscoverySession>());
last_discovery_session_alias_ = discovery_session.get();
// Restarting the discovery session.
EXPECT_CALL(*adapter_, StartDiscoverySessionWithFilterRaw(_, _, _))
.WillOnce(SaveArg<1>(&discovery_callback));
connection_finder_.AdapterPresentChanged(adapter_.get(), true);
connection_finder_.AdapterPoweredChanged(adapter_.get(), true);
ON_CALL(*last_discovery_session_alias_, IsActive())
.WillByDefault(Return(true));
ASSERT_FALSE(discovery_callback.is_null());
discovery_callback.Run(std::move(discovery_session));
// Preparing to create a GATT connection to the right device.
PrepareDevice(kEidForPreviousTimeQuantum);
cryptauth::FakeConnection* connection =
connection_finder_.ExpectCreateConnection();
// Trying to create a connection.
connection_finder_.DeviceAdded(adapter_.get(), device_.get());
// Completing the connection.
base::RunLoop run_loop;
ASSERT_FALSE(last_found_connection_);
connection->SetStatus(cryptauth::Connection::Status::IN_PROGRESS);
connection->SetStatus(cryptauth::Connection::Status::CONNECTED);
run_loop.RunUntilIdle();
EXPECT_TRUE(last_found_connection_);
}
} // namespace proximity_auth
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment