blob: 222bc3882f99b921aae18ebfca402cd1f33b5e4b [file] [log] [blame]
// Copyright 2016 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/services/secure_channel/ble_weave_client_connection.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/timer/mock_timer.h"
#include "base/timer/timer.h"
#include "chromeos/components/multidevice/remote_device_ref.h"
#include "chromeos/components/multidevice/remote_device_test_util.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/secure_channel/connection_observer.h"
#include "chromeos/services/secure_channel/fake_wire_message.h"
#include "chromeos/services/secure_channel/wire_message.h"
#include "device/bluetooth/bluetooth_adapter_factory.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_characteristic.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.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::SaveArg;
using testing::StrictMock;
namespace chromeos {
namespace secure_channel {
namespace weave {
namespace {
typedef BluetoothLowEnergyWeaveClientConnection::SubStatus SubStatus;
typedef BluetoothLowEnergyWeavePacketReceiver::State ReceiverState;
typedef BluetoothLowEnergyWeavePacketReceiver::ReceiverError ReceiverError;
typedef BluetoothLowEnergyWeavePacketReceiver::ReceiverType ReceiverType;
const char kTestFeature[] = "testFeature";
const char kServiceUUID[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEEF";
const char kTXCharacteristicUUID[] = "977c6674-1239-4e72-993b-502369b8bb5a";
const char kRXCharacteristicUUID[] = "f4b904a2-a030-43b3-98a8-221c536c03cb";
const char kServiceID[] = "service id";
const char kTXCharacteristicID[] = "TX characteristic id";
const char kRXCharacteristicID[] = "RX characteristic id";
const char kTestRemoteDeviceBluetoothAddress[] = "AA:BB:CC:DD:EE:FF";
const device::BluetoothRemoteGattCharacteristic::Properties
kCharacteristicProperties =
device::BluetoothRemoteGattCharacteristic::PROPERTY_BROADCAST |
device::BluetoothRemoteGattCharacteristic::PROPERTY_READ |
device::BluetoothRemoteGattCharacteristic::
PROPERTY_WRITE_WITHOUT_RESPONSE |
device::BluetoothRemoteGattCharacteristic::PROPERTY_INDICATE;
const int kMaxNumberOfTries = 3;
const uint16_t kLargeMaxPacketSize = 30;
const uint8_t kDataHeader = 0;
const uint8_t kConnectionRequestHeader = 1;
const uint8_t kSmallConnectionResponseHeader = 2;
const uint8_t kLargeConnectionResponseHeader = 3;
const uint8_t kConnectionCloseHeader = 4;
const uint8_t kErroneousHeader = 5;
const std::string kSmallMessage = "bb";
const std::string kLargeMessage = "aaabbb";
const std::string kLargeMessage0 = "aaa";
const std::string kLargeMessage1 = "bbb";
const Packet kConnectionRequest{kConnectionRequestHeader};
const Packet kSmallConnectionResponse{kSmallConnectionResponseHeader};
const Packet kLargeConnectionResponse{kLargeConnectionResponseHeader};
const Packet kConnectionCloseSuccess{kConnectionCloseHeader,
ReasonForClose::CLOSE_WITHOUT_ERROR};
const Packet kConnectionCloseUnknownError{kConnectionCloseHeader,
ReasonForClose::UNKNOWN_ERROR};
const Packet kConnectionCloseApplicationError{
kConnectionCloseHeader, ReasonForClose::APPLICATION_ERROR};
const Packet kSmallPackets0 = Packet{kDataHeader, 'b', 'b'};
const Packet kLargePackets0 = Packet{kDataHeader, 'a', 'a', 'a'};
const Packet kLargePackets1 = Packet{kDataHeader, 'b', 'b', 'b'};
const Packet kErroneousPacket = Packet{kErroneousHeader};
const std::vector<Packet> kSmallPackets{kSmallPackets0};
const std::vector<Packet> kLargePackets{kLargePackets0, kLargePackets1};
class MockBluetoothLowEnergyWeavePacketGenerator
: public BluetoothLowEnergyWeavePacketGenerator {
public:
MockBluetoothLowEnergyWeavePacketGenerator()
: max_packet_size_(kDefaultMaxPacketSize) {}
Packet CreateConnectionRequest() override { return kConnectionRequest; }
Packet CreateConnectionResponse() override {
NOTIMPLEMENTED();
return Packet();
}
Packet CreateConnectionClose(ReasonForClose reason_for_close) override {
return Packet{kConnectionCloseHeader,
static_cast<uint8_t>(reason_for_close)};
}
void SetMaxPacketSize(uint16_t size) override { max_packet_size_ = size; }
std::vector<Packet> EncodeDataMessage(std::string message) override {
if (message == (std::string(kTestFeature) + "," + kSmallMessage) &&
max_packet_size_ == kDefaultMaxPacketSize) {
return kSmallPackets;
} else if (message == (std::string(kTestFeature) + "," + kLargeMessage) &&
max_packet_size_ == kLargeMaxPacketSize) {
return kLargePackets;
} else {
NOTREACHED();
return std::vector<Packet>();
}
}
uint16_t GetMaxPacketSize() { return max_packet_size_; }
private:
uint16_t max_packet_size_;
};
class MockBluetoothLowEnergyWeavePacketReceiver
: public BluetoothLowEnergyWeavePacketReceiver {
public:
MockBluetoothLowEnergyWeavePacketReceiver()
: BluetoothLowEnergyWeavePacketReceiver(ReceiverType::CLIENT),
state_(State::CONNECTING),
max_packet_size_(kDefaultMaxPacketSize),
reason_for_close_(ReasonForClose::CLOSE_WITHOUT_ERROR),
reason_to_close_(ReasonForClose::CLOSE_WITHOUT_ERROR) {}
ReceiverState GetState() override { return state_; }
uint16_t GetMaxPacketSize() override { return max_packet_size_; }
ReasonForClose GetReasonForClose() override { return reason_for_close_; }
ReasonForClose GetReasonToClose() override { return reason_to_close_; }
std::string GetDataMessage() override {
if (max_packet_size_ == kDefaultMaxPacketSize) {
return kSmallMessage;
} else {
return kLargeMessage;
}
}
ReceiverError GetReceiverError() override {
return ReceiverError::NO_ERROR_DETECTED;
}
ReceiverState ReceivePacket(const Packet& packet) override {
switch (packet[0]) {
case kSmallConnectionResponseHeader:
max_packet_size_ = kDefaultMaxPacketSize;
state_ = ReceiverState::WAITING;
break;
case kLargeConnectionResponseHeader:
max_packet_size_ = kLargeMaxPacketSize;
state_ = ReceiverState::WAITING;
break;
case kConnectionCloseHeader:
state_ = ReceiverState::CONNECTION_CLOSED;
reason_for_close_ = static_cast<ReasonForClose>(packet[1]);
break;
case kDataHeader:
if (packet == kSmallPackets0 || packet == kLargePackets1) {
state_ = ReceiverState::DATA_READY;
} else {
state_ = ReceiverState::RECEIVING_DATA;
}
break;
default:
reason_to_close_ = ReasonForClose::APPLICATION_ERROR;
state_ = ReceiverState::ERROR_DETECTED;
}
return state_;
}
private:
ReceiverState state_;
uint16_t max_packet_size_;
ReasonForClose reason_for_close_;
ReasonForClose reason_to_close_;
};
class TestBluetoothLowEnergyWeaveClientConnection
: public BluetoothLowEnergyWeaveClientConnection {
public:
TestBluetoothLowEnergyWeaveClientConnection(
chromeos::multidevice::RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::MockBluetoothDevice* mock_bluetooth_device,
bool should_set_low_connection_latency)
: BluetoothLowEnergyWeaveClientConnection(
remote_device,
adapter,
remote_service_uuid,
mock_bluetooth_device,
should_set_low_connection_latency) {}
~TestBluetoothLowEnergyWeaveClientConnection() override {}
bool should_set_low_connection_latency() {
return BluetoothLowEnergyWeaveClientConnection::
should_set_low_connection_latency();
}
MOCK_METHOD2(
CreateCharacteristicsFinder,
BluetoothLowEnergyCharacteristicsFinder*(
const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
success,
const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback& error));
MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes));
// Exposing inherited protected methods for testing.
using BluetoothLowEnergyWeaveClientConnection::DestroyConnection;
using BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged;
using BluetoothLowEnergyWeaveClientConnection::SetupTestDoubles;
// Exposing inherited protected fields for testing.
using BluetoothLowEnergyWeaveClientConnection::status;
using BluetoothLowEnergyWeaveClientConnection::sub_status;
private:
DISALLOW_COPY_AND_ASSIGN(TestBluetoothLowEnergyWeaveClientConnection);
};
class MockBluetoothLowEnergyCharacteristicsFinder
: public BluetoothLowEnergyCharacteristicsFinder {
public:
MockBluetoothLowEnergyCharacteristicsFinder() {}
~MockBluetoothLowEnergyCharacteristicsFinder() override {}
private:
DISALLOW_COPY_AND_ASSIGN(MockBluetoothLowEnergyCharacteristicsFinder);
};
class MockConnectionObserver : public ConnectionObserver {
public:
MockConnectionObserver(Connection* connection)
: connection_(connection),
num_send_completed_(0),
delete_on_disconnect_(false),
delete_on_message_sent_(false) {}
std::string GetLastDeserializedMessage() {
return last_deserialized_message_;
}
bool last_send_success() { return last_send_success_; }
int num_send_completed() { return num_send_completed_; }
bool delete_on_disconnect() { return delete_on_disconnect_; }
void set_delete_on_disconnect(bool delete_on_disconnect) {
delete_on_disconnect_ = delete_on_disconnect;
}
void set_delete_on_message_sent(bool delete_on_message_sent) {
delete_on_message_sent_ = delete_on_message_sent;
}
// ConnectionObserver:
void OnConnectionStatusChanged(Connection* connection,
Connection::Status old_status,
Connection::Status new_status) override {
if (new_status == Connection::Status::DISCONNECTED && delete_on_disconnect_)
delete connection_;
}
void OnMessageReceived(const Connection& connection,
const WireMessage& message) override {}
void OnSendCompleted(const Connection& conenction,
const WireMessage& message,
bool success) override {
last_deserialized_message_ = message.payload();
last_send_success_ = success;
num_send_completed_++;
if (delete_on_message_sent_)
delete connection_;
}
private:
Connection* connection_;
std::string last_deserialized_message_;
bool last_send_success_;
int num_send_completed_;
bool delete_on_disconnect_;
bool delete_on_message_sent_;
};
} // namespace
class SecureChannelBluetoothLowEnergyWeaveClientConnectionTest
: public testing::Test {
public:
SecureChannelBluetoothLowEnergyWeaveClientConnectionTest()
: remote_device_(chromeos::multidevice::CreateRemoteDeviceRefForTest()),
service_uuid_(device::BluetoothUUID(kServiceUUID)),
tx_characteristic_uuid_(device::BluetoothUUID(kTXCharacteristicUUID)),
rx_characteristic_uuid_(device::BluetoothUUID(kRXCharacteristicUUID)) {}
~SecureChannelBluetoothLowEnergyWeaveClientConnectionTest() override {}
void SetUp() override {
test_timer_ = nullptr;
generator_ = nullptr;
receiver_ = nullptr;
has_verified_connection_result_ = false;
connection_observer_.reset();
adapter_ = base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
mock_bluetooth_device_ =
std::make_unique<NiceMock<device::MockBluetoothDevice>>(
adapter_.get(), 0, chromeos::multidevice::kTestRemoteDeviceName,
kTestRemoteDeviceBluetoothAddress, false, false);
service_ = std::make_unique<NiceMock<device::MockBluetoothGattService>>(
mock_bluetooth_device_.get(), kServiceID, service_uuid_, true, false);
tx_characteristic_ =
std::make_unique<NiceMock<device::MockBluetoothGattCharacteristic>>(
service_.get(), kTXCharacteristicID, tx_characteristic_uuid_, false,
kCharacteristicProperties,
device::BluetoothRemoteGattCharacteristic::PERMISSION_NONE);
rx_characteristic_ =
std::make_unique<NiceMock<device::MockBluetoothGattCharacteristic>>(
service_.get(), kRXCharacteristicID, rx_characteristic_uuid_, false,
kCharacteristicProperties,
device::BluetoothRemoteGattCharacteristic::PERMISSION_NONE);
std::vector<const device::BluetoothDevice*> devices;
devices.push_back(mock_bluetooth_device_.get());
ON_CALL(*adapter_, GetDevices()).WillByDefault(Return(devices));
ON_CALL(*adapter_, GetDevice(kTestRemoteDeviceBluetoothAddress))
.WillByDefault(Return(mock_bluetooth_device_.get()));
ON_CALL(*mock_bluetooth_device_, GetGattService(kServiceID))
.WillByDefault(Return(service_.get()));
ON_CALL(*mock_bluetooth_device_, IsConnected()).WillByDefault(Return(true));
ON_CALL(*mock_bluetooth_device_, GetConnectionInfo(_))
.WillByDefault(Invoke(
this, &SecureChannelBluetoothLowEnergyWeaveClientConnectionTest::
MockGetConnectionInfo));
ON_CALL(*service_, GetCharacteristic(kRXCharacteristicID))
.WillByDefault(Return(rx_characteristic_.get()));
ON_CALL(*service_, GetCharacteristic(kTXCharacteristicID))
.WillByDefault(Return(tx_characteristic_.get()));
device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
}
void TearDown() override { connection_observer_.reset(); }
// Creates a BluetoothLowEnergyWeaveClientConnection and verifies it's in
// DISCONNECTED state.
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> CreateConnection(
bool should_set_low_connection_latency) {
EXPECT_CALL(*adapter_, AddObserver(_));
EXPECT_CALL(*adapter_, RemoveObserver(_));
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
new TestBluetoothLowEnergyWeaveClientConnection(
remote_device_, adapter_, service_uuid_,
mock_bluetooth_device_.get(), should_set_low_connection_latency));
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
// Add the mock observer to observe on OnDidMessageSend.
connection_observer_ =
base::WrapUnique(new MockConnectionObserver(connection.get()));
connection->AddObserver(connection_observer_.get());
test_timer_ = new base::MockOneShotTimer();
generator_ = new NiceMock<MockBluetoothLowEnergyWeavePacketGenerator>();
receiver_ = new NiceMock<MockBluetoothLowEnergyWeavePacketReceiver>();
connection->SetupTestDoubles(task_runner_, base::WrapUnique(test_timer_),
base::WrapUnique(generator_),
base::WrapUnique(receiver_));
return connection;
}
// Transitions |connection| from DISCONNECTED to WAITING_CHARACTERISTICS
// state, without an existing GATT connection.
void ConnectGatt(TestBluetoothLowEnergyWeaveClientConnection* connection) {
if (connection->should_set_low_connection_latency()) {
EXPECT_CALL(*mock_bluetooth_device_,
SetConnectionLatency(
device::BluetoothDevice::CONNECTION_LATENCY_LOW, _, _))
.WillOnce(DoAll(SaveArg<1>(&connection_latency_callback_),
SaveArg<2>(&connection_latency_error_callback_)));
}
// Preparing |connection| for a CreateGattConnection call.
EXPECT_CALL(*mock_bluetooth_device_, CreateGattConnection(_, _))
.WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_),
SaveArg<1>(&create_gatt_connection_error_callback_)));
connection->Connect();
if (connection->should_set_low_connection_latency()) {
// Handle setting the connection latency.
EXPECT_EQ(connection->sub_status(),
SubStatus::WAITING_CONNECTION_LATENCY);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
connection_latency_callback_.Run();
}
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_GATT_CONNECTION);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Preparing |connection| to run |create_gatt_connection_success_callback_|.
EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
ASSERT_FALSE(create_gatt_connection_success_callback_.is_null());
EXPECT_CALL(*connection, CreateCharacteristicsFinder(_, _))
.WillOnce(DoAll(
SaveArg<0>(&characteristics_finder_success_callback_),
SaveArg<1>(&characteristics_finder_error_callback_),
Return(new NiceMock<MockBluetoothLowEnergyCharacteristicsFinder>)));
create_gatt_connection_success_callback_.Run(
std::make_unique<NiceMock<device::MockBluetoothGattConnection>>(
adapter_, kTestRemoteDeviceBluetoothAddress));
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CHARACTERISTICS);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_CHARACTERISTICS to
// WAITING_NOTIFY_SESSION state.
void CharacteristicsFound(
TestBluetoothLowEnergyWeaveClientConnection* connection) {
EXPECT_CALL(*rx_characteristic_, StartNotifySession(_, _))
.WillOnce(DoAll(SaveArg<0>(&notify_session_success_callback_),
SaveArg<1>(&notify_session_error_callback_)));
EXPECT_FALSE(characteristics_finder_error_callback_.is_null());
ASSERT_FALSE(characteristics_finder_success_callback_.is_null());
characteristics_finder_success_callback_.Run(
{service_uuid_, kServiceID},
{tx_characteristic_uuid_, kTXCharacteristicID},
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_NOTIFY_SESSION);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_NOTIFY_SESSION to
// WAITING_CONNECTION_RESPONSE state.
void NotifySessionStarted(
TestBluetoothLowEnergyWeaveClientConnection* connection) {
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
EXPECT_FALSE(notify_session_error_callback_.is_null());
ASSERT_FALSE(notify_session_success_callback_.is_null());
// Store an alias for the notify session passed |connection|.
std::unique_ptr<device::MockBluetoothGattNotifySession> notify_session(
new NiceMock<device::MockBluetoothGattNotifySession>(
tx_characteristic_->GetWeakPtr()));
notify_session_success_callback_.Run(std::move(notify_session));
task_runner_->RunUntilIdle();
VerifyGattNotifySessionResult(true);
// Written value contains only the mock Connection Request.
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionRequest);
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_RESPONSE);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_CONNECTION_RESPONSE to CONNECTED.
void ConnectionResponseReceived(
TestBluetoothLowEnergyWeaveClientConnection* connection,
uint16_t selected_packet_size) {
// Written value contains only the mock Connection Request.
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionRequest);
// OnDidSendMessage is not called.
EXPECT_EQ(0, connection_observer_->num_send_completed());
RunWriteCharacteristicSuccessCallback();
// Received Connection Response.
if (selected_packet_size == kDefaultMaxPacketSize) {
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kSmallConnectionResponse);
EXPECT_EQ(receiver_->GetMaxPacketSize(), kDefaultMaxPacketSize);
EXPECT_EQ(generator_->GetMaxPacketSize(), kDefaultMaxPacketSize);
} else if (selected_packet_size == kLargeMaxPacketSize) {
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kLargeConnectionResponse);
EXPECT_EQ(receiver_->GetMaxPacketSize(), kLargeMaxPacketSize);
EXPECT_EQ(generator_->GetMaxPacketSize(), kLargeMaxPacketSize);
} else {
NOTREACHED();
}
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
EXPECT_EQ(connection->status(), Connection::Status::CONNECTED);
}
// Transitions |connection| to a DISCONNECTED state regardless of its initial
// state.
void Disconnect(TestBluetoothLowEnergyWeaveClientConnection* connection) {
if (connection->IsConnected()) {
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
}
connection->Disconnect();
if (connection->IsConnected()) {
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseSuccess);
RunWriteCharacteristicSuccessCallback();
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
}
void DeleteConnectionWithoutCallingDisconnect(
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection>*
connection) {
bool was_connected = (*connection)->IsConnected();
if (was_connected) {
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
}
connection->reset();
}
void InitializeConnection(
TestBluetoothLowEnergyWeaveClientConnection* connection,
uint32_t selected_packet_size) {
ConnectGatt(connection);
CharacteristicsFound(connection);
NotifySessionStarted(connection);
ConnectionResponseReceived(connection, selected_packet_size);
}
void RunWriteCharacteristicSuccessCallback() {
EXPECT_FALSE(write_remote_characteristic_error_callback_.is_null());
ASSERT_FALSE(write_remote_characteristic_success_callback_.is_null());
write_remote_characteristic_success_callback_.Run();
task_runner_->RunUntilIdle();
}
void VerifyGattConnectionResultSuccess() {
histogram_tester_.ExpectUniqueSample(
"ProximityAuth.BluetoothGattConnectionResult",
BluetoothLowEnergyWeaveClientConnection::GattConnectionResult::
GATT_CONNECTION_RESULT_SUCCESS,
1);
}
void VerifyGattNotifySessionResult(bool success) {
histogram_tester_.ExpectUniqueSample(
"ProximityAuth.BluetoothGattNotifySessionResult",
GattServiceOperationResultSuccessOrFailure(success), 1);
}
void VerifyGattWriteCharacteristicResult(bool success, int num_writes) {
histogram_tester_.ExpectBucketCount(
"ProximityAuth.BluetoothGattWriteCharacteristicResult",
GattServiceOperationResultSuccessOrFailure(success), num_writes);
}
void VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult
expected_result) {
histogram_tester_.ExpectUniqueSample(
"ProximityAuth.BleWeaveConnectionResult", expected_result, 1);
has_verified_connection_result_ = true;
}
BluetoothLowEnergyWeaveClientConnection::GattServiceOperationResult
GattServiceOperationResultSuccessOrFailure(bool success) {
return success ? BluetoothLowEnergyWeaveClientConnection::
GattServiceOperationResult::
GATT_SERVICE_OPERATION_RESULT_SUCCESS
: BluetoothLowEnergyWeaveClientConnection::
GattServiceOperationResult::
GATT_SERVICE_OPERATION_RESULT_GATT_ERROR_UNKNOWN;
}
base::Optional<int32_t> GetRssi(
TestBluetoothLowEnergyWeaveClientConnection* connection) {
connection->GetConnectionRssi(base::BindOnce(
&SecureChannelBluetoothLowEnergyWeaveClientConnectionTest::
OnConnectionRssi,
base::Unretained(this)));
base::Optional<int32_t> rssi = rssi_;
rssi_.reset();
return rssi;
}
protected:
const chromeos::multidevice::RemoteDeviceRef remote_device_;
const device::BluetoothUUID service_uuid_;
const device::BluetoothUUID tx_characteristic_uuid_;
const device::BluetoothUUID rx_characteristic_uuid_;
const proximity_auth::ScopedDisableLoggingForTesting disable_logging_;
scoped_refptr<device::MockBluetoothAdapter> adapter_;
base::MockOneShotTimer* test_timer_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
std::unique_ptr<device::MockBluetoothDevice> mock_bluetooth_device_;
std::unique_ptr<device::MockBluetoothGattService> service_;
std::unique_ptr<device::MockBluetoothGattCharacteristic> tx_characteristic_;
std::unique_ptr<device::MockBluetoothGattCharacteristic> rx_characteristic_;
std::vector<uint8_t> last_value_written_on_tx_characteristic_;
base::test::ScopedTaskEnvironment task_environment_;
int32_t rssi_for_channel_ = device::BluetoothDevice::kUnknownPower;
bool last_wire_message_success_;
bool has_verified_connection_result_;
NiceMock<MockBluetoothLowEnergyWeavePacketGenerator>* generator_;
NiceMock<MockBluetoothLowEnergyWeavePacketReceiver>* receiver_;
std::unique_ptr<MockConnectionObserver> connection_observer_;
// Callbacks
base::Closure connection_latency_callback_;
device::BluetoothDevice::ErrorCallback connection_latency_error_callback_;
device::BluetoothDevice::GattConnectionCallback
create_gatt_connection_success_callback_;
device::BluetoothDevice::ConnectErrorCallback
create_gatt_connection_error_callback_;
BluetoothLowEnergyCharacteristicsFinder::SuccessCallback
characteristics_finder_success_callback_;
BluetoothLowEnergyCharacteristicsFinder::ErrorCallback
characteristics_finder_error_callback_;
device::BluetoothRemoteGattCharacteristic::NotifySessionCallback
notify_session_success_callback_;
device::BluetoothRemoteGattCharacteristic::ErrorCallback
notify_session_error_callback_;
base::Closure write_remote_characteristic_success_callback_;
device::BluetoothRemoteGattCharacteristic::ErrorCallback
write_remote_characteristic_error_callback_;
base::HistogramTester histogram_tester_;
private:
void MockGetConnectionInfo(
const device::BluetoothDevice::ConnectionInfoCallback& callback) {
callback.Run(device::BluetoothDevice::ConnectionInfo(
rssi_for_channel_, 0 /* transmit_power */, 0 /* max_transmit_power */));
}
void OnConnectionRssi(base::Optional<int32_t> rssi) { rssi_ = rssi; }
base::Optional<int32_t> rssi_;
DISALLOW_COPY_AND_ASSIGN(
SecureChannelBluetoothLowEnergyWeaveClientConnectionTest);
};
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
CreateAndDestroyWithoutConnectCallDoesntCrash) {
std::unique_ptr<BluetoothLowEnergyWeaveClientConnection> connection =
std::make_unique<BluetoothLowEnergyWeaveClientConnection>(
remote_device_, adapter_, service_uuid_, mock_bluetooth_device_.get(),
true /* should_set_low_connection_latency */);
connection.reset();
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
DisconnectWithoutConnectDoesntCrash) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
Disconnect(connection.get());
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectSuccess) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectSuccessDisconnect) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
Disconnect(connection.get());
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectThenBluetoothDisconnects) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
connection->DeviceConnectedStateChanged(adapter_.get(),
mock_bluetooth_device_.get(),
false /* is_now_connected */);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
DisconnectCalledTwice) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
// Call Disconnect() twice; this should only result in one "close connection"
// message (verified via WillOnce() above).
connection->Disconnect();
connection->Disconnect();
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionCloseSuccess);
RunWriteCharacteristicSuccessCallback();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectSuccessDisconnect_DoNotSetLowLatency) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(false /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
Disconnect(connection.get());
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectIncompleteDisconnectFromWaitingCharacteristicsState) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
Disconnect(connection.get());
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectIncompleteDisconnectFromWaitingNotifySessionState) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
Disconnect(connection.get());
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectIncompleteDisconnectFromWaitingConnectionResponseState) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
Disconnect(connection.get());
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectFailsCharacteristicsNotFound) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
EXPECT_CALL(*rx_characteristic_, StartNotifySession(_, _)).Times(0);
EXPECT_FALSE(characteristics_finder_success_callback_.is_null());
ASSERT_FALSE(characteristics_finder_error_callback_.is_null());
characteristics_finder_error_callback_.Run(
{tx_characteristic_uuid_, kTXCharacteristicID},
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_FINDING_GATT_CHARACTERISTICS);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectFailsCharacteristicsFoundThenUnavailable) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
// Simulate the inability to fetch the characteristic after it was received.
// This would most likely be due to the Bluetooth device or service being
// removed during a connection attempt. See crbug.com/756174.
EXPECT_CALL(*service_, GetCharacteristic(_)).WillOnce(Return(nullptr));
EXPECT_FALSE(characteristics_finder_error_callback_.is_null());
ASSERT_FALSE(characteristics_finder_success_callback_.is_null());
characteristics_finder_success_callback_.Run(
{service_uuid_, kServiceID},
{tx_characteristic_uuid_, kTXCharacteristicID},
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_GATT_CHARACTERISTIC_NOT_AVAILABLE);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectFailsNotifySessionError) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _)).Times(0);
EXPECT_FALSE(notify_session_success_callback_.is_null());
ASSERT_FALSE(notify_session_error_callback_.is_null());
notify_session_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
VerifyGattNotifySessionResult(false);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_STARTING_NOTIFY_SESSION);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectFailsErrorSendingConnectionRequest) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
// |connection| will call WriteRemoteCharacteristics(_,_) to try to send the
// message |kMaxNumberOfTries| times. There is alredy one EXPECT_CALL for
// WriteRemoteCharacteristic(_,_,_) in NotifySessionStated, that's why we use
// |kMaxNumberOfTries-1| in the EXPECT_CALL statement.
EXPECT_EQ(0, connection_observer_->num_send_completed());
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.Times(kMaxNumberOfTries - 1)
.WillRepeatedly(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
for (int i = 0; i < kMaxNumberOfTries; i++) {
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionRequest);
ASSERT_FALSE(write_remote_characteristic_error_callback_.is_null());
EXPECT_FALSE(write_remote_characteristic_success_callback_.is_null());
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
VerifyGattWriteCharacteristicResult(false /* success */,
i + 1 /* num_writes */);
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ReceiveMessageSmallerThanCharacteristicSize) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
std::string received_bytes;
EXPECT_CALL(*connection, OnBytesReceived(_))
.WillOnce(SaveArg<0>(&received_bytes));
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kSmallPackets0);
EXPECT_EQ(received_bytes, kSmallMessage);
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ReceiveMessageLargerThanCharacteristicSize) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kLargeMaxPacketSize);
std::string received_bytes;
EXPECT_CALL(*connection, OnBytesReceived(_))
.WillOnce(SaveArg<0>(&received_bytes));
std::vector<Packet> packets = kLargePackets;
for (auto packet : packets) {
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), packet);
}
EXPECT_EQ(received_bytes, kLargeMessage);
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
SendMessageSmallerThanCharacteristicSize) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
// Expecting a first call of WriteRemoteCharacteristic, after SendMessage is
// called.
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kSmallMessage, kTestFeature));
EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(1, connection_observer_->num_send_completed());
EXPECT_EQ(kSmallMessage, connection_observer_->GetLastDeserializedMessage());
EXPECT_TRUE(connection_observer_->last_send_success());
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
SendMessageLargerThanCharacteristicSize) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kLargeMaxPacketSize);
// Expecting a first call of WriteRemoteCharacteristic, after SendMessage is
// called.
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kLargeMessage, kTestFeature));
EXPECT_EQ(last_value_written_on_tx_characteristic_, kLargePackets0);
std::vector<uint8_t> bytes_received(
last_value_written_on_tx_characteristic_.begin() + 1,
last_value_written_on_tx_characteristic_.end());
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
bytes_received.insert(bytes_received.end(),
last_value_written_on_tx_characteristic_.begin() + 1,
last_value_written_on_tx_characteristic_.end());
std::vector<uint8_t> expected(kLargeMessage.begin(), kLargeMessage.end());
EXPECT_EQ(expected, bytes_received);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 3 /* num_writes */);
EXPECT_EQ(1, connection_observer_->num_send_completed());
EXPECT_EQ(kLargeMessage, connection_observer_->GetLastDeserializedMessage());
EXPECT_TRUE(connection_observer_->last_send_success());
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
SendMessageKeepsFailing) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.Times(kMaxNumberOfTries)
.WillRepeatedly(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kSmallMessage, kTestFeature));
for (int i = 0; i < kMaxNumberOfTries; i++) {
EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
ASSERT_FALSE(write_remote_characteristic_error_callback_.is_null());
EXPECT_FALSE(write_remote_characteristic_success_callback_.is_null());
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
VerifyGattWriteCharacteristicResult(false /* success */,
i + 1 /* num_writes */);
if (i == kMaxNumberOfTries - 1) {
EXPECT_EQ(1, connection_observer_->num_send_completed());
EXPECT_EQ(kSmallMessage,
connection_observer_->GetLastDeserializedMessage());
EXPECT_FALSE(connection_observer_->last_send_success());
} else {
EXPECT_EQ(0, connection_observer_->num_send_completed());
}
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ReceiveCloseConnectionTest) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kConnectionCloseUnknownError);
EXPECT_EQ(receiver_->GetReasonForClose(), ReasonForClose::UNKNOWN_ERROR);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ReceiverErrorTest) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kErroneousPacket);
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseApplicationError);
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ReceiverErrorWithPendingWritesTest) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kLargeMaxPacketSize);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kLargeMessage, kTestFeature));
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kErroneousPacket);
EXPECT_EQ(last_value_written_on_tx_characteristic_, kLargePackets0);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseApplicationError);
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 3 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
// Test for fix to crbug.com/708744. Without the fix, this test will crash.
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ObserverDeletesConnectionOnDisconnect) {
TestBluetoothLowEnergyWeaveClientConnection* connection =
CreateConnection(true /* should_set_low_connection_latency */).release();
connection_observer_->set_delete_on_disconnect(true);
InitializeConnection(connection, kDefaultMaxPacketSize);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->GattCharacteristicValueChanged(
adapter_.get(), rx_characteristic_.get(), kErroneousPacket);
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseApplicationError);
EXPECT_EQ(receiver_->GetReasonToClose(), ReasonForClose::APPLICATION_ERROR);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
// We cannot check if connection's status and sub_status are DISCONNECTED
// because it has been deleted.
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
// Test for fix to crbug.com/ 751884. Without the fix, this test will crash.
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ObserverDeletesConnectionOnMessageSent) {
TestBluetoothLowEnergyWeaveClientConnection* connection =
CreateConnection(true /* should_set_low_connection_latency */).release();
connection_observer_->set_delete_on_message_sent(true);
InitializeConnection(connection, kDefaultMaxPacketSize);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.Times(2)
.WillRepeatedly(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kSmallMessage, kTestFeature));
EXPECT_EQ(last_value_written_on_tx_characteristic_, kSmallPackets0);
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
task_runner_->RunUntilIdle();
EXPECT_EQ(1, connection_observer_->num_send_completed());
EXPECT_EQ(kSmallMessage, connection_observer_->GetLastDeserializedMessage());
EXPECT_TRUE(connection_observer_->last_send_success());
// Connection close packet should have been sent when the object was deleted.
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionCloseSuccess);
// We cannot check if connection's status and sub_status are DISCONNECTED
// because it has been deleted.
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
WriteConnectionCloseMaxNumberOfTimes) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
connection->Disconnect();
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_SENDING_MESSAGE);
for (int i = 0; i < kMaxNumberOfTries; i++) {
EXPECT_EQ(last_value_written_on_tx_characteristic_,
kConnectionCloseSuccess);
ASSERT_FALSE(write_remote_characteristic_error_callback_.is_null());
EXPECT_FALSE(write_remote_characteristic_success_callback_.is_null());
if (i != kMaxNumberOfTries - 1) {
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _))
.WillOnce(
DoAll(SaveArg<0>(&last_value_written_on_tx_characteristic_),
SaveArg<1>(&write_remote_characteristic_success_callback_),
SaveArg<2>(&write_remote_characteristic_error_callback_)));
}
write_remote_characteristic_error_callback_.Run(
device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
task_runner_->RunUntilIdle();
VerifyGattWriteCharacteristicResult(false /* success */,
i + 1 /* num_writes */);
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_WRITING_GATT_CHARACTERISTIC);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
ConnectAfterADelayWhenThrottled) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
EXPECT_CALL(*mock_bluetooth_device_,
SetConnectionLatency(
device::BluetoothDevice::CONNECTION_LATENCY_LOW, _, _))
.WillOnce(DoAll(SaveArg<1>(&connection_latency_callback_),
SaveArg<2>(&connection_latency_error_callback_)));
EXPECT_CALL(*mock_bluetooth_device_, CreateGattConnection(_, _))
.WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_),
SaveArg<1>(&create_gatt_connection_error_callback_)));
// No GATT connection should be created before the delay.
connection->Connect();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
EXPECT_TRUE(create_gatt_connection_error_callback_.is_null());
EXPECT_TRUE(create_gatt_connection_success_callback_.is_null());
// A GATT connection should be created after the delay and after setting the
// connection latency.
task_runner_->RunUntilIdle();
ASSERT_FALSE(connection_latency_callback_.is_null());
connection_latency_callback_.Run();
EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
ASSERT_FALSE(create_gatt_connection_success_callback_.is_null());
// Preparing |connection| to run |create_gatt_connection_success_callback_|.
EXPECT_CALL(*connection, CreateCharacteristicsFinder(_, _))
.WillOnce(DoAll(
SaveArg<0>(&characteristics_finder_success_callback_),
SaveArg<1>(&characteristics_finder_error_callback_),
Return(new NiceMock<MockBluetoothLowEnergyCharacteristicsFinder>)));
create_gatt_connection_success_callback_.Run(
std::make_unique<NiceMock<device::MockBluetoothGattConnection>>(
adapter_, kTestRemoteDeviceBluetoothAddress));
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
VerifyGattConnectionResultSuccess();
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
SetConnectionLatencyError) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
EXPECT_CALL(*mock_bluetooth_device_,
SetConnectionLatency(
device::BluetoothDevice::CONNECTION_LATENCY_LOW, _, _))
.WillOnce(DoAll(SaveArg<1>(&connection_latency_callback_),
SaveArg<2>(&connection_latency_error_callback_)));
// Even if setting the connection interval fails, we should still connect.
connection->Connect();
ASSERT_FALSE(connection_latency_error_callback_.is_null());
EXPECT_CALL(*mock_bluetooth_device_, CreateGattConnection(_, _))
.WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_),
SaveArg<1>(&create_gatt_connection_error_callback_)));
connection_latency_error_callback_.Run();
EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
ASSERT_FALSE(create_gatt_connection_success_callback_.is_null());
// Preparing |connection| to run |create_gatt_connection_success_callback_|.
EXPECT_CALL(*connection, CreateCharacteristicsFinder(_, _))
.WillOnce(DoAll(
SaveArg<0>(&characteristics_finder_success_callback_),
SaveArg<1>(&characteristics_finder_error_callback_),
Return(new NiceMock<MockBluetoothLowEnergyCharacteristicsFinder>)));
create_gatt_connection_success_callback_.Run(
std::make_unique<NiceMock<device::MockBluetoothGattConnection>>(
adapter_, kTestRemoteDeviceBluetoothAddress));
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
ConnectionResponseReceived(connection.get(), kDefaultMaxPacketSize);
VerifyGattConnectionResultSuccess();
DeleteConnectionWithoutCallingDisconnect(&connection);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_ConnectionLatency) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
EXPECT_CALL(*mock_bluetooth_device_,
SetConnectionLatency(
device::BluetoothDevice::CONNECTION_LATENCY_LOW, _, _))
.WillOnce(DoAll(SaveArg<1>(&connection_latency_callback_),
SaveArg<2>(&connection_latency_error_callback_)));
// Call Connect(), which should set the connection latency.
connection->Connect();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_SETTING_CONNECTION_LATENCY);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_GattConnection) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
EXPECT_CALL(*mock_bluetooth_device_,
SetConnectionLatency(
device::BluetoothDevice::CONNECTION_LATENCY_LOW, _, _))
.WillOnce(DoAll(SaveArg<1>(&connection_latency_callback_),
SaveArg<2>(&connection_latency_error_callback_)));
// Preparing |connection| for a CreateGattConnection call.
EXPECT_CALL(*mock_bluetooth_device_, CreateGattConnection(_, _))
.WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_),
SaveArg<1>(&create_gatt_connection_error_callback_)));
connection->Connect();
// Handle setting the connection latency.
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
connection_latency_callback_.Run();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_GATT_CONNECTION);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_CREATING_GATT_CONNECTION);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_GattCharacteristics) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CHARACTERISTICS);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_FINDING_GATT_CHARACTERISTICS);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_NotifySession) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_NOTIFY_SESSION);
EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_STARTING_NOTIFY_SESSION);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_ConnectionResponse) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
NotifySessionStarted(connection.get());
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_CONNECTION_RESPONSE);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest,
Timeout_SendingMessage) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
EXPECT_CALL(*tx_characteristic_, WriteRemoteCharacteristic(_, _, _));
connection->SendMessage(
std::make_unique<FakeWireMessage>(kSmallMessage, kTestFeature));
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_SENDING_MESSAGE);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_TIMEOUT_WAITING_FOR_MESSAGE_TO_SEND);
}
TEST_F(SecureChannelBluetoothLowEnergyWeaveClientConnectionTest, GetRssi) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
EXPECT_FALSE(GetRssi(connection.get()));
rssi_for_channel_ = -50;
EXPECT_EQ(-50, GetRssi(connection.get()));
rssi_for_channel_ = -40;
EXPECT_EQ(-40, GetRssi(connection.get()));
rssi_for_channel_ = -30;
EXPECT_EQ(-30, GetRssi(connection.get()));
}
} // namespace weave
} // namespace secure_channel
} // namespace chromeos