| // 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/components/tether/ble_connection_manager.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/timer/mock_timer.h" |
| #include "base/unguessable_token.h" |
| #include "chromeos/components/multidevice/remote_device_test_util.h" |
| #include "chromeos/components/tether/fake_ble_advertiser.h" |
| #include "chromeos/components/tether/fake_ble_scanner.h" |
| #include "chromeos/components/tether/proto/tether.pb.h" |
| #include "chromeos/components/tether/timer_factory.h" |
| #include "chromeos/services/secure_channel/ble_constants.h" |
| #include "chromeos/services/secure_channel/ble_weave_client_connection.h" |
| #include "chromeos/services/secure_channel/connection.h" |
| #include "chromeos/services/secure_channel/fake_connection.h" |
| #include "chromeos/services/secure_channel/fake_secure_channel_connection.h" |
| #include "components/cryptauth/fake_secure_message_delegate.h" |
| #include "device/bluetooth/test/mock_bluetooth_adapter.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| using testing::NiceMock; |
| using testing::Return; |
| |
| namespace chromeos { |
| |
| namespace tether { |
| |
| namespace { |
| |
| const char kTetherFeature[] = "magic_tether"; |
| |
| const char kBluetoothAddress1[] = "11:22:33:44:55:66"; |
| const char kBluetoothAddress2[] = "22:33:44:55:66:77"; |
| const char kBluetoothAddress3[] = "33:44:55:66:77:88"; |
| |
| struct SecureChannelStatusChange { |
| SecureChannelStatusChange( |
| const std::string& device_id, |
| const secure_channel::SecureChannel::Status& old_status, |
| const secure_channel::SecureChannel::Status& new_status, |
| BleConnectionManager::StateChangeDetail status_change_detail) |
| : device_id(device_id), |
| old_status(old_status), |
| new_status(new_status), |
| status_change_detail(status_change_detail) {} |
| |
| std::string device_id; |
| secure_channel::SecureChannel::Status old_status; |
| secure_channel::SecureChannel::Status new_status; |
| BleConnectionManager::StateChangeDetail status_change_detail; |
| }; |
| |
| struct ReceivedMessage { |
| ReceivedMessage(const std::string& device_id, const std::string& payload) |
| : device_id(device_id), payload(payload) {} |
| |
| std::string device_id; |
| std::string payload; |
| }; |
| |
| class MockTimerFactory : public TimerFactory { |
| public: |
| std::unique_ptr<base::OneShotTimer> CreateOneShotTimer() override { |
| return std::make_unique<base::MockOneShotTimer>(); |
| } |
| }; |
| |
| // Observer used in all tests except for ObserverUnregisters() which tracks all |
| // status changes and messages received. |
| class TestObserver final : public BleConnectionManager::Observer { |
| public: |
| TestObserver() = default; |
| |
| // BleConnectionManager::Observer: |
| void OnSecureChannelStatusChanged( |
| const std::string& device_id, |
| const secure_channel::SecureChannel::Status& old_status, |
| const secure_channel::SecureChannel::Status& new_status, |
| BleConnectionManager::StateChangeDetail status_change_detail) override { |
| connection_status_changes_.emplace_back(device_id, old_status, new_status, |
| status_change_detail); |
| } |
| |
| void OnMessageReceived(const std::string& device_id, |
| const std::string& payload) override { |
| received_messages_.push_back(ReceivedMessage(device_id, payload)); |
| } |
| |
| void OnMessageSent(int sequence_number) override { |
| sent_sequence_numbers_.push_back(sequence_number); |
| } |
| |
| const std::vector<SecureChannelStatusChange>& connection_status_changes() { |
| return connection_status_changes_; |
| } |
| |
| const std::vector<ReceivedMessage>& received_messages() { |
| return received_messages_; |
| } |
| |
| const std::vector<int>& sent_sequence_numbers() { |
| return sent_sequence_numbers_; |
| } |
| |
| private: |
| std::vector<SecureChannelStatusChange> connection_status_changes_; |
| std::vector<ReceivedMessage> received_messages_; |
| std::vector<int> sent_sequence_numbers_; |
| }; |
| |
| // Observer used in ObserverUnregisters() which unregisters a device when it |
| // receives a callback from the manager. The device it unregisters is the same |
| // one it receives the event about. |
| class UnregisteringObserver : public BleConnectionManager::Observer { |
| public: |
| UnregisteringObserver(BleConnectionManager* manager, |
| const base::UnguessableToken& request_id) |
| : manager_(manager), request_id_(request_id) {} |
| |
| // BleConnectionManager::Observer: |
| void OnSecureChannelStatusChanged( |
| const std::string& device_id, |
| const secure_channel::SecureChannel::Status& old_status, |
| const secure_channel::SecureChannel::Status& new_status, |
| BleConnectionManager::StateChangeDetail status_change_detail) override { |
| manager_->UnregisterRemoteDevice(device_id, request_id_); |
| } |
| |
| void OnMessageReceived(const std::string& device_id, |
| const std::string& payload) override { |
| manager_->UnregisterRemoteDevice(device_id, request_id_); |
| } |
| |
| void OnMessageSent(int sequence_number) override { NOTIMPLEMENTED(); } |
| |
| private: |
| BleConnectionManager* manager_; |
| const base::UnguessableToken request_id_; |
| }; |
| |
| class TestMetricsObserver final : public BleConnectionManager::MetricsObserver { |
| public: |
| TestMetricsObserver() = default; |
| |
| bool HasDeviceStartedScan(const std::string& device_id) { |
| return base::ContainsKey(device_id_started_scan_set_, device_id); |
| } |
| |
| bool HasDeviceReceivedAdvertisement( |
| const std::string& device_id, |
| bool is_background_advertisement_expected) { |
| return base::ContainsKey(device_id_to_received_advertisement_map_, |
| device_id) && |
| device_id_to_received_advertisement_map_[device_id] == |
| is_background_advertisement_expected; |
| } |
| |
| bool HasDeviceConnected(const std::string& device_id, |
| bool is_background_advertisement_expected) { |
| return base::ContainsKey(device_id_to_connected_map_, device_id) && |
| device_id_to_connected_map_[device_id] == |
| is_background_advertisement_expected; |
| } |
| |
| bool HasDeviceCreatedSecureChannel( |
| const std::string& device_id, |
| bool is_background_advertisement_expected) { |
| return base::ContainsKey(device_id_to_secure_channel_created_map_, |
| device_id) && |
| device_id_to_secure_channel_created_map_[device_id] == |
| is_background_advertisement_expected; |
| } |
| |
| bool HasDeviceDisconnected( |
| const std::string& device_id, |
| BleConnectionManager::StateChangeDetail expected_state_change_detail, |
| bool is_background_advertisement_expected) { |
| if (!base::ContainsKey(device_id_to_disconnected_map_, device_id)) |
| return false; |
| |
| for (std::pair<BleConnectionManager::StateChangeDetail, bool> event_pair : |
| device_id_to_disconnected_map_[device_id]) { |
| if (event_pair.first == expected_state_change_detail && |
| event_pair.second == is_background_advertisement_expected) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // BleConnectionManager::MetricsObserver: |
| void OnConnectionAttemptStarted(const std::string& device_id) override { |
| device_id_started_scan_set_.insert(device_id); |
| } |
| |
| void OnAdvertisementReceived(const std::string& device_id, |
| bool is_background_advertisement) override { |
| device_id_to_received_advertisement_map_[device_id] = |
| is_background_advertisement; |
| } |
| |
| void OnConnection(const std::string& device_id, |
| bool is_background_advertisement) override { |
| device_id_to_connected_map_[device_id] = is_background_advertisement; |
| } |
| |
| void OnSecureChannelCreated(const std::string& device_id, |
| bool is_background_advertisement) override { |
| device_id_to_secure_channel_created_map_[device_id] = |
| is_background_advertisement; |
| } |
| |
| void OnDeviceDisconnected( |
| const std::string& device_id, |
| BleConnectionManager::StateChangeDetail state_change_detail, |
| bool is_background_advertisement) override { |
| device_id_to_disconnected_map_[device_id].push_back( |
| std::make_pair(state_change_detail, is_background_advertisement)); |
| } |
| |
| private: |
| std::set<std::string> device_id_started_scan_set_; |
| |
| // Maps to whether the call indicated that it was a background advertisement. |
| std::map<std::string, bool> device_id_to_received_advertisement_map_; |
| std::map<std::string, bool> device_id_to_connected_map_; |
| std::map<std::string, bool> device_id_to_secure_channel_created_map_; |
| |
| // The |second| item tracks if the call indicated that it was a background |
| // advertisement. |
| std::map< |
| std::string, |
| std::vector<std::pair<BleConnectionManager::StateChangeDetail, bool>>> |
| device_id_to_disconnected_map_; |
| }; |
| |
| class FakeConnectionWithAddress : public secure_channel::FakeConnection { |
| public: |
| FakeConnectionWithAddress(multidevice::RemoteDeviceRef remote_device, |
| const std::string& device_address) |
| : FakeConnection(remote_device, false /* should_auto_connect */), |
| device_address_(device_address) {} |
| |
| // secure_channel::Connection: |
| std::string GetDeviceAddress() override { return device_address_; } |
| |
| private: |
| const std::string device_address_; |
| }; |
| |
| class FakeConnectionFactory final |
| : public secure_channel::weave::BluetoothLowEnergyWeaveClientConnection:: |
| Factory { |
| public: |
| FakeConnectionFactory( |
| scoped_refptr<device::BluetoothAdapter> expected_adapter, |
| const device::BluetoothUUID expected_remote_service_uuid) |
| : expected_adapter_(expected_adapter), |
| expected_remote_service_uuid_(expected_remote_service_uuid) {} |
| |
| std::unique_ptr<secure_channel::Connection> BuildInstance( |
| multidevice::RemoteDeviceRef remote_device, |
| scoped_refptr<device::BluetoothAdapter> adapter, |
| const device::BluetoothUUID remote_service_uuid, |
| device::BluetoothDevice* bluetooth_device, |
| bool should_set_low_connection_latency) override { |
| EXPECT_EQ(expected_adapter_, adapter); |
| EXPECT_EQ(expected_remote_service_uuid_, remote_service_uuid); |
| EXPECT_FALSE(should_set_low_connection_latency); |
| return base::WrapUnique(new FakeConnectionWithAddress( |
| remote_device, bluetooth_device->GetAddress())); |
| } |
| |
| private: |
| scoped_refptr<device::BluetoothAdapter> expected_adapter_; |
| const device::BluetoothUUID expected_remote_service_uuid_; |
| }; |
| |
| multidevice::RemoteDeviceRefList CreateTestDevices(size_t num_to_create) { |
| return multidevice::CreateRemoteDeviceRefListForTest(num_to_create); |
| } |
| |
| } // namespace |
| |
| class BleConnectionManagerTest : public testing::Test { |
| protected: |
| class FakeSecureChannelConnection |
| : public secure_channel::FakeSecureChannelConnection { |
| public: |
| explicit FakeSecureChannelConnection( |
| std::unique_ptr<secure_channel::Connection> connection) |
| : secure_channel::FakeSecureChannelConnection(std::move(connection)) {} |
| ~FakeSecureChannelConnection() override = default; |
| |
| void AddObserver(Observer* observer) override { |
| secure_channel::FakeSecureChannelConnection::AddObserver(observer); |
| |
| EXPECT_EQ(static_cast<size_t>(1), observers().size()); |
| } |
| |
| void RemoveObserver(Observer* observer) override { |
| secure_channel::FakeSecureChannelConnection::RemoveObserver(observer); |
| EXPECT_EQ(static_cast<size_t>(0), observers().size()); |
| } |
| }; |
| |
| class FakeSecureChannelFactory final |
| : public secure_channel::SecureChannel::Factory { |
| public: |
| FakeSecureChannelFactory() = default; |
| |
| std::vector<FakeSecureChannelConnection*>& created_channels() { |
| return created_channels_; |
| } |
| |
| void SetExpectedDeviceAddress(const std::string& expected_device_address) { |
| expected_device_address_ = expected_device_address; |
| } |
| |
| std::unique_ptr<secure_channel::SecureChannel> BuildInstance( |
| std::unique_ptr<secure_channel::Connection> connection) override { |
| FakeConnectionWithAddress* fake_connection = |
| static_cast<FakeConnectionWithAddress*>(connection.get()); |
| EXPECT_EQ(expected_device_address_, fake_connection->GetDeviceAddress()); |
| FakeSecureChannelConnection* channel = |
| new FakeSecureChannelConnection(std::move(connection)); |
| created_channels_.push_back(channel); |
| return base::WrapUnique(channel); |
| } |
| |
| private: |
| std::string expected_device_address_; |
| std::vector<FakeSecureChannelConnection*> created_channels_; |
| }; |
| |
| BleConnectionManagerTest() : test_devices_(CreateTestDevices(4)) { |
| // These tests assume a maximum of two concurrent advertisers. Some of the |
| // multi-device tests would need to be re-written if this constant changes. |
| EXPECT_EQ(2u, secure_channel::kMaxConcurrentAdvertisements); |
| } |
| |
| void SetUp() override { |
| verified_status_changes_.clear(); |
| verified_received_messages_.clear(); |
| |
| mock_adapter_ = |
| base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); |
| |
| device_queue_ = std::make_unique<BleAdvertisementDeviceQueue>(); |
| |
| fake_ble_advertiser_ = std::make_unique<FakeBleAdvertiser>( |
| true /* automatically_update_active_advertisements */); |
| |
| fake_ble_scanner_ = std::make_unique<FakeBleScanner>( |
| true /* automatically_update_discovery_session */); |
| |
| fake_connection_factory_ = base::WrapUnique(new FakeConnectionFactory( |
| mock_adapter_, device::BluetoothUUID(secure_channel::kGattServerUuid))); |
| secure_channel::weave::BluetoothLowEnergyWeaveClientConnection::Factory:: |
| SetInstanceForTesting(fake_connection_factory_.get()); |
| |
| fake_secure_channel_factory_ = |
| base::WrapUnique(new FakeSecureChannelFactory()); |
| secure_channel::SecureChannel::Factory::SetInstanceForTesting( |
| fake_secure_channel_factory_.get()); |
| |
| manager_ = base::WrapUnique(new BleConnectionManager( |
| mock_adapter_, device_queue_.get(), fake_ble_advertiser_.get(), |
| fake_ble_scanner_.get())); |
| test_observer_ = base::WrapUnique(new TestObserver()); |
| manager_->AddObserver(test_observer_.get()); |
| test_metrics_observer_ = base::WrapUnique(new TestMetricsObserver()); |
| manager_->AddMetricsObserver(test_metrics_observer_.get()); |
| |
| mock_timer_factory_ = new MockTimerFactory(); |
| manager_->SetTestTimerFactoryForTesting( |
| base::WrapUnique(mock_timer_factory_)); |
| } |
| |
| void TearDown() override { |
| // All state changes should have already been verified. This ensures that |
| // no test has missed one. |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>(), |
| used_background_advertisements_); |
| |
| // Same with received messages. |
| VerifyReceivedMessages(std::vector<ReceivedMessage>()); |
| } |
| |
| void VerifyConnectionStateChanges( |
| const std::vector<SecureChannelStatusChange>& expected_changes, |
| bool is_background_advertisement = false) { |
| verified_status_changes_.insert(verified_status_changes_.end(), |
| expected_changes.begin(), |
| expected_changes.end()); |
| |
| ASSERT_EQ(verified_status_changes_.size(), |
| test_observer_->connection_status_changes().size()); |
| |
| for (size_t i = 0; i < verified_status_changes_.size(); i++) { |
| EXPECT_EQ(verified_status_changes_[i].device_id, |
| test_observer_->connection_status_changes()[i].device_id); |
| EXPECT_EQ(verified_status_changes_[i].old_status, |
| test_observer_->connection_status_changes()[i].old_status); |
| EXPECT_EQ(verified_status_changes_[i].new_status, |
| test_observer_->connection_status_changes()[i].new_status); |
| EXPECT_EQ( |
| verified_status_changes_[i].status_change_detail, |
| test_observer_->connection_status_changes()[i].status_change_detail); |
| |
| if (verified_status_changes_[i].new_status == |
| secure_channel::SecureChannel::Status::CONNECTING) { |
| EXPECT_TRUE(test_metrics_observer_->HasDeviceStartedScan( |
| verified_status_changes_[i].device_id)); |
| } else if (verified_status_changes_[i].new_status == |
| secure_channel::SecureChannel::Status::CONNECTED) { |
| EXPECT_TRUE(test_metrics_observer_->HasDeviceConnected( |
| verified_status_changes_[i].device_id, |
| is_background_advertisement)); |
| } else if (verified_status_changes_[i].new_status == |
| secure_channel::SecureChannel::Status::AUTHENTICATED) { |
| EXPECT_TRUE(test_metrics_observer_->HasDeviceCreatedSecureChannel( |
| verified_status_changes_[i].device_id, |
| is_background_advertisement)); |
| } else if (verified_status_changes_[i].new_status == |
| secure_channel::SecureChannel::Status::DISCONNECTED) { |
| EXPECT_TRUE(test_metrics_observer_->HasDeviceDisconnected( |
| verified_status_changes_[i].device_id, |
| verified_status_changes_[i].status_change_detail, |
| is_background_advertisement)); |
| } |
| } |
| } |
| |
| void VerifyReceivedMessages( |
| const std::vector<ReceivedMessage>& expected_messages) { |
| verified_received_messages_.insert(verified_received_messages_.end(), |
| expected_messages.begin(), |
| expected_messages.end()); |
| |
| ASSERT_EQ(verified_received_messages_.size(), |
| test_observer_->received_messages().size()); |
| |
| for (size_t i = 0; i < verified_received_messages_.size(); i++) { |
| EXPECT_EQ(verified_received_messages_[i].device_id, |
| test_observer_->received_messages()[i].device_id); |
| EXPECT_EQ(verified_received_messages_[i].payload, |
| test_observer_->received_messages()[i].payload); |
| } |
| } |
| |
| void VerifyNoTimeoutSet(multidevice::RemoteDeviceRef remote_device) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| EXPECT_TRUE(connection_metadata); |
| EXPECT_FALSE( |
| connection_metadata->connection_attempt_timeout_timer_->IsRunning()); |
| } |
| |
| void VerifyFailImmediatelyTimeoutSet( |
| multidevice::RemoteDeviceRef remote_device) { |
| VerifyTimeoutSet(remote_device, |
| BleConnectionManager::kFailImmediatelyTimeoutMillis); |
| } |
| |
| void VerifyAdvertisingTimeoutSet(multidevice::RemoteDeviceRef remote_device) { |
| VerifyTimeoutSet(remote_device, |
| BleConnectionManager::kAdvertisingTimeoutMillis); |
| } |
| |
| void VerifyTimeoutSet(multidevice::RemoteDeviceRef remote_device, |
| int64_t expected_num_millis) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| EXPECT_TRUE(connection_metadata); |
| EXPECT_TRUE( |
| connection_metadata->connection_attempt_timeout_timer_->IsRunning()); |
| EXPECT_EQ(base::TimeDelta::FromMilliseconds(expected_num_millis), |
| connection_metadata->connection_attempt_timeout_timer_ |
| ->GetCurrentDelay()); |
| } |
| |
| void FireTimerForDevice(multidevice::RemoteDeviceRef remote_device) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| EXPECT_TRUE(connection_metadata); |
| EXPECT_TRUE( |
| connection_metadata->connection_attempt_timeout_timer_->IsRunning()); |
| static_cast<base::MockOneShotTimer*>( |
| connection_metadata->connection_attempt_timeout_timer_.get()) |
| ->Fire(); |
| } |
| |
| void NotifyReceivedAdvertisementFromDevice( |
| const std::string& bluetooth_address, |
| multidevice::RemoteDeviceRef remote_device, |
| bool is_background_advertisement) { |
| device::MockBluetoothDevice device( |
| mock_adapter_.get(), 0u /* bluetooth_class */, "name", |
| bluetooth_address, false /* paired */, false /* connected */); |
| fake_ble_scanner_->NotifyReceivedAdvertisementFromDevice( |
| remote_device, &device, is_background_advertisement); |
| } |
| |
| FakeSecureChannelConnection* GetChannelForDevice( |
| multidevice::RemoteDeviceRef remote_device) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| EXPECT_TRUE(connection_metadata); |
| EXPECT_TRUE(connection_metadata->secure_channel_); |
| return static_cast<FakeSecureChannelConnection*>( |
| connection_metadata->secure_channel_.get()); |
| } |
| |
| void VerifyDeviceRegistered(multidevice::RemoteDeviceRef remote_device) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| EXPECT_TRUE(connection_metadata); |
| } |
| |
| void VerifyDeviceNotRegistered(multidevice::RemoteDeviceRef remote_device) { |
| BleConnectionManager::ConnectionMetadata* connection_metadata = |
| manager_->GetConnectionMetadata(remote_device.GetDeviceId()); |
| if (connection_metadata) |
| EXPECT_FALSE(connection_metadata->HasPendingConnectionRequests()); |
| } |
| |
| // Registers |remote_device|, creates a connection to that device at |
| // |bluetooth_address|, and authenticates the resulting channel. |
| FakeSecureChannelConnection* ConnectSuccessfully( |
| multidevice::RemoteDeviceRef remote_device, |
| const std::string& bluetooth_address, |
| const base::UnguessableToken& request_id, |
| bool is_background_advertisement) { |
| manager_->RegisterRemoteDevice(remote_device.GetDeviceId(), request_id, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(remote_device); |
| VerifyConnectionStateChanges( |
| std::vector<SecureChannelStatusChange>{ |
| {remote_device.GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_NONE}}, |
| is_background_advertisement); |
| |
| FakeSecureChannelConnection* channel = |
| ReceiveAdvertisementAndConnectChannel(remote_device, bluetooth_address, |
| is_background_advertisement); |
| AuthenticateChannel(remote_device, is_background_advertisement); |
| return channel; |
| } |
| |
| // Creates a connection to |remote_device| at |bluetooth_address|. The device |
| // must be registered before calling this function. |
| FakeSecureChannelConnection* ReceiveAdvertisementAndConnectChannel( |
| multidevice::RemoteDeviceRef remote_device, |
| const std::string& bluetooth_address, |
| bool is_background_advertisement) { |
| VerifyDeviceRegistered(remote_device); |
| |
| fake_secure_channel_factory_->SetExpectedDeviceAddress(bluetooth_address); |
| |
| NotifyReceivedAdvertisementFromDevice(bluetooth_address, remote_device, |
| is_background_advertisement); |
| |
| return GetChannelForDevice(remote_device); |
| } |
| |
| // Authenticates the SecureChannel associated with |remote_device|. The device |
| // must be registered and already have an associated channel before calling |
| // this function. |
| void AuthenticateChannel(multidevice::RemoteDeviceRef remote_device, |
| bool is_background_advertisement) { |
| VerifyDeviceRegistered(remote_device); |
| |
| FakeSecureChannelConnection* channel = GetChannelForDevice(remote_device); |
| DCHECK(channel); |
| |
| num_expected_authenticated_channels_++; |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::CONNECTED); |
| |
| channel->ChangeStatus( |
| secure_channel::SecureChannel::Status::AUTHENTICATING); |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::AUTHENTICATED); |
| |
| VerifyConnectionStateChanges( |
| std::vector<SecureChannelStatusChange>{ |
| {remote_device.GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::CONNECTED, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}, |
| {remote_device.GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTED, |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}, |
| {remote_device.GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_NONE}}, |
| is_background_advertisement); |
| } |
| |
| void VerifyLastMessageSent(FakeSecureChannelConnection* channel, |
| int sequence_number, |
| const std::string& payload, |
| size_t expected_size) { |
| ASSERT_EQ(expected_size, channel->sent_messages().size()); |
| secure_channel::FakeSecureChannelConnection::SentMessage sent_message = |
| channel->sent_messages()[expected_size - 1]; |
| EXPECT_EQ(kTetherFeature, sent_message.feature); |
| EXPECT_EQ(payload, sent_message.payload); |
| |
| std::vector<int> sent_sequence_numbers_before_finished = |
| test_observer_->sent_sequence_numbers(); |
| channel->CompleteSendingMessage(sequence_number); |
| std::vector<int> sent_sequence_numbers_after_finished = |
| test_observer_->sent_sequence_numbers(); |
| EXPECT_EQ(sent_sequence_numbers_before_finished.size() + 1u, |
| sent_sequence_numbers_after_finished.size()); |
| EXPECT_EQ(sequence_number, sent_sequence_numbers_after_finished.back()); |
| } |
| |
| const multidevice::RemoteDeviceRefList test_devices_; |
| |
| scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; |
| std::unique_ptr<FakeBleAdvertiser> fake_ble_advertiser_; |
| std::unique_ptr<FakeBleScanner> fake_ble_scanner_; |
| std::unique_ptr<BleAdvertisementDeviceQueue> device_queue_; |
| MockTimerFactory* mock_timer_factory_; |
| std::unique_ptr<FakeConnectionFactory> fake_connection_factory_; |
| std::unique_ptr<FakeSecureChannelFactory> fake_secure_channel_factory_; |
| std::unique_ptr<TestObserver> test_observer_; |
| std::unique_ptr<TestMetricsObserver> test_metrics_observer_; |
| |
| std::vector<SecureChannelStatusChange> verified_status_changes_; |
| std::vector<ReceivedMessage> verified_received_messages_; |
| bool used_background_advertisements_ = false; |
| |
| std::unique_ptr<BleConnectionManager> manager_; |
| |
| int num_expected_authenticated_channels_ = 0; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(BleConnectionManagerTest); |
| }; |
| |
| TEST_F(BleConnectionManagerTest, TestCannotScan) { |
| fake_ble_scanner_->set_should_fail_to_register(true); |
| |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestCannotAdvertise) { |
| fake_ble_advertiser_->set_should_fail_to_start_advertising(true); |
| |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestRegistersButNoResult) { |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestRegistersAndUnregister_NoConnection) { |
| base::UnguessableToken request_id = base::UnguessableToken::Create(); |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestRegisterWithNoConnection_TimeoutOccurs) { |
| base::UnguessableToken request_id = base::UnguessableToken::Create(); |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| FireTimerForDevice(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestSuccessfulConnection_FailsAuthentication) { |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| fake_secure_channel_factory_->SetExpectedDeviceAddress(kBluetoothAddress1); |
| NotifyReceivedAdvertisementFromDevice( |
| kBluetoothAddress1, test_devices_[0], |
| false /* is_background_advertisement */); |
| FakeSecureChannelConnection* channel = GetChannelForDevice(test_devices_[0]); |
| |
| // Should not result in an additional "disconnected => connecting" broadcast. |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::CONNECTING); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>()); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::CONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::CONNECTED, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::AUTHENTICATING); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTED, |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Fail authentication, which should automatically start a retry. |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_GATT_CONNECTION_WAS_ATTEMPTED}, |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestSuccessfulConnection_SendAndReceive) { |
| base::UnguessableToken request_id = base::UnguessableToken::Create(); |
| FakeSecureChannelConnection* channel = |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, request_id, |
| false /* is_background_advertisement */); |
| |
| int sequence_number = |
| manager_->SendMessage(test_devices_[0].GetDeviceId(), "request1"); |
| VerifyLastMessageSent(channel, sequence_number, "request1", 1); |
| |
| channel->ReceiveMessage(kTetherFeature, "response1"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response1"}}); |
| |
| sequence_number = |
| manager_->SendMessage(test_devices_[0].GetDeviceId(), "request2"); |
| VerifyLastMessageSent(channel, sequence_number, "request2", 2); |
| |
| channel->ReceiveMessage(kTetherFeature, "response2"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response2"}}); |
| |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, |
| TestSuccessfulConnection_BackgroundAdvertisement) { |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, |
| base::UnguessableToken::Create(), |
| true /* is_background_advertisement */); |
| used_background_advertisements_ = true; |
| } |
| |
| // Test for fix to crbug.com/706640. This test will crash without the fix. |
| TEST_F(BleConnectionManagerTest, |
| TestSuccessfulConnection_MultipleAdvertisementsReceived) { |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| fake_secure_channel_factory_->SetExpectedDeviceAddress(kBluetoothAddress1); |
| |
| // Simulate multiple advertisements being received: |
| NotifyReceivedAdvertisementFromDevice( |
| kBluetoothAddress1, test_devices_[0], |
| false /* is_background_advertisement */); |
| FakeSecureChannelConnection* channel = GetChannelForDevice(test_devices_[0]); |
| |
| NotifyReceivedAdvertisementFromDevice( |
| kBluetoothAddress1, test_devices_[0], |
| false /* is_background_advertisement */); |
| // Verify that a new channel has not been created: |
| EXPECT_EQ(channel, GetChannelForDevice(test_devices_[0])); |
| |
| NotifyReceivedAdvertisementFromDevice( |
| kBluetoothAddress1, test_devices_[0], |
| false /* is_background_advertisement */); |
| // Verify that a new channel has not been created: |
| EXPECT_EQ(channel, GetChannelForDevice(test_devices_[0])); |
| } |
| |
| TEST_F(BleConnectionManagerTest, |
| TestSuccessfulConnection_MultipleConnectionReasons) { |
| base::UnguessableToken request_id_1 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_2 = base::UnguessableToken::Create(); |
| |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, request_id_1, |
| false /* is_background_advertisement */); |
| |
| // Now, register a different connection reason. |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id_2, |
| secure_channel::ConnectionPriority::kLow); |
| |
| // Unregister the |TETHER_AVAILABILITY_REQUEST| reason, but leave the |
| // |CONNECT_TETHERING_REQUEST| registered. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_1); |
| VerifyDeviceRegistered(test_devices_[0]); |
| |
| // Now, unregister the other reason; this should cause the device to be |
| // fully unregistered. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_2); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TestGetStatusForDevice) { |
| base::UnguessableToken request_id = base::UnguessableToken::Create(); |
| secure_channel::SecureChannel::Status status; |
| |
| // Should return false when the device has not yet been registered at all. |
| EXPECT_FALSE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Should be CONNECTING at this point. |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::CONNECTING, status); |
| |
| fake_secure_channel_factory_->SetExpectedDeviceAddress(kBluetoothAddress1); |
| NotifyReceivedAdvertisementFromDevice( |
| kBluetoothAddress1, test_devices_[0], |
| false /* is_background_advertisement */); |
| FakeSecureChannelConnection* channel = GetChannelForDevice(test_devices_[0]); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::CONNECTING); |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::CONNECTING, status); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::CONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::CONNECTED, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::CONNECTED, status); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::AUTHENTICATING); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTED, |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::AUTHENTICATING, status); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::AUTHENTICATED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATING, |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::AUTHENTICATED, status); |
| |
| // Now, unregister the device. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| EXPECT_TRUE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| EXPECT_EQ(secure_channel::SecureChannel::Status::DISCONNECTING, status); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| EXPECT_FALSE( |
| manager_->GetStatusForDevice(test_devices_[0].GetDeviceId(), &status)); |
| } |
| |
| TEST_F(BleConnectionManagerTest, |
| TestSuccessfulConnection_DisconnectsAfterConnection) { |
| FakeSecureChannelConnection* channel = ConnectSuccessfully( |
| test_devices_[0], kBluetoothAddress1, base::UnguessableToken::Create(), |
| false /* is_background_advertisement */); |
| |
| channel->ChangeStatus(secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_GATT_CONNECTION_WAS_ATTEMPTED}, |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TwoDevices_NeitherCanScan) { |
| fake_ble_scanner_->set_should_fail_to_register(true); |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| manager_->RegisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TwoDevices_NeitherCanAdvertise) { |
| fake_ble_advertiser_->set_should_fail_to_start_advertising(true); |
| |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| manager_->RegisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| base::UnguessableToken::Create(), |
| secure_channel::ConnectionPriority::kLow); |
| VerifyFailImmediatelyTimeoutSet(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, |
| TwoDevices_RegisterWithNoConnection_TimerFires) { |
| base::UnguessableToken request_id_1 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_2 = base::UnguessableToken::Create(); |
| |
| // Register device 0. |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id_1, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Register device 1. |
| manager_->RegisterRemoteDevice(test_devices_[1].GetDeviceId(), request_id_2, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Simulate timeout for device 0 by firing timeout. |
| FireTimerForDevice(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Simulate timeout for device 1 by firing timeout. |
| FireTimerForDevice(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Unregister device 0. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_1); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| // Unregister device 1. |
| manager_->UnregisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| request_id_2); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TwoDevices_OneConnects) { |
| base::UnguessableToken request_id_1 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_2 = base::UnguessableToken::Create(); |
| |
| // Successfully connect to device 0. |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, request_id_1, |
| false /* is_background_advertisement */); |
| |
| // Register device 1. |
| manager_->RegisterRemoteDevice(test_devices_[1].GetDeviceId(), request_id_2, |
| secure_channel::ConnectionPriority::kLow); |
| VerifyAdvertisingTimeoutSet(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Simulate timeout for device 1 by firing timeout. |
| FireTimerForDevice(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Unregister device 0. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_1); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| // Unregister device 1. |
| manager_->UnregisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| request_id_2); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, TwoDevices_BothConnectSendAndReceive) { |
| base::UnguessableToken request_id_1 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_2 = base::UnguessableToken::Create(); |
| |
| FakeSecureChannelConnection* channel0 = |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, request_id_1, |
| false /* is_background_advertisement */); |
| |
| FakeSecureChannelConnection* channel1 = |
| ConnectSuccessfully(test_devices_[1], kBluetoothAddress2, request_id_2, |
| false /* is_background_advertisement */); |
| |
| int sequence_number = |
| manager_->SendMessage(test_devices_[0].GetDeviceId(), "request1_device0"); |
| VerifyLastMessageSent(channel0, sequence_number, "request1_device0", 1); |
| |
| sequence_number = |
| manager_->SendMessage(test_devices_[1].GetDeviceId(), "request1_device1"); |
| VerifyLastMessageSent(channel1, sequence_number, "request1_device1", 1); |
| |
| channel0->ReceiveMessage(kTetherFeature, "response1_device0"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response1_device0"}}); |
| |
| channel1->ReceiveMessage(kTetherFeature, "response1_device1"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[1].GetDeviceId(), "response1_device1"}}); |
| |
| sequence_number = |
| manager_->SendMessage(test_devices_[0].GetDeviceId(), "request2_device0"); |
| VerifyLastMessageSent(channel0, sequence_number, "request2_device0", 2); |
| |
| sequence_number = |
| manager_->SendMessage(test_devices_[1].GetDeviceId(), "request2_device1"); |
| VerifyLastMessageSent(channel1, sequence_number, "request2_device1", 2); |
| |
| channel0->ReceiveMessage(kTetherFeature, "response2_device0"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response2_device0"}}); |
| |
| channel1->ReceiveMessage(kTetherFeature, "response2_device1"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[1].GetDeviceId(), "response2_device1"}}); |
| |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_1); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| manager_->UnregisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| request_id_2); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| VerifyDeviceNotRegistered(test_devices_[1]); |
| |
| fake_secure_channel_factory_->created_channels()[1]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| TEST_F(BleConnectionManagerTest, FourDevices_ComprehensiveTest) { |
| base::UnguessableToken request_id_1 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_2 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_3 = base::UnguessableToken::Create(); |
| base::UnguessableToken request_id_4 = base::UnguessableToken::Create(); |
| |
| // Register all devices. Since the maximum number of simultaneous connection |
| // attempts is 2, only devices 0 and 1 should actually start connecting. |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id_1, |
| secure_channel::ConnectionPriority::kLow); |
| manager_->RegisterRemoteDevice(test_devices_[1].GetDeviceId(), request_id_2, |
| secure_channel::ConnectionPriority::kLow); |
| manager_->RegisterRemoteDevice(test_devices_[2].GetDeviceId(), request_id_3, |
| secure_channel::ConnectionPriority::kLow); |
| manager_->RegisterRemoteDevice(test_devices_[3].GetDeviceId(), request_id_4, |
| secure_channel::ConnectionPriority::kLow); |
| |
| // Devices 0 and 1 should be advertising; devices 2 and 3 should not be. |
| VerifyAdvertisingTimeoutSet(test_devices_[0]); |
| VerifyAdvertisingTimeoutSet(test_devices_[1]); |
| VerifyNoTimeoutSet(test_devices_[2]); |
| VerifyNoTimeoutSet(test_devices_[3]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}, |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Device 0 connects successfully. |
| FakeSecureChannelConnection* channel0 = ReceiveAdvertisementAndConnectChannel( |
| test_devices_[0], kBluetoothAddress1, |
| false /* is_background_advertisement */); |
| |
| // Since device 0 has connected, advertising to that device is no longer |
| // necessary. Device 2 should have filled up that advertising slot. |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[2].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Meanwhile, device 1 fails to connect, so the timeout fires. The advertising |
| // slot left by device 1 creates space for device 3 to start connecting. |
| FireTimerForDevice(test_devices_[1]); |
| VerifyAdvertisingTimeoutSet(test_devices_[3]); |
| VerifyNoTimeoutSet(test_devices_[1]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[3].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Now, device 0 authenticates and sends and receives a message. |
| AuthenticateChannel(test_devices_[0], |
| false /* is_background_advertisement */); |
| int sequence_number = |
| manager_->SendMessage(test_devices_[0].GetDeviceId(), "request1"); |
| VerifyLastMessageSent(channel0, sequence_number, "request1", 1); |
| |
| channel0->ReceiveMessage(kTetherFeature, "response1"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response1"}}); |
| |
| // Now, device 0 is unregistered. |
| manager_->UnregisterRemoteDevice(test_devices_[0].GetDeviceId(), |
| request_id_1); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| // Device 2 fails to connect, so the timeout fires. Device 1 takes its spot. |
| FireTimerForDevice(test_devices_[2]); |
| VerifyAdvertisingTimeoutSet(test_devices_[1]); |
| VerifyNoTimeoutSet(test_devices_[2]); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[2].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_COULD_NOT_ATTEMPT_CONNECTION}, |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Device 3 connects successfully. |
| FakeSecureChannelConnection* channel3 = ReceiveAdvertisementAndConnectChannel( |
| test_devices_[3], kBluetoothAddress3, |
| false /* is_background_advertisement */); |
| |
| // Since device 3 has connected, device 2 starts connecting again. |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[2].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| |
| // Now, device 3 authenticates and sends and receives a message. |
| AuthenticateChannel(test_devices_[3], |
| false /* is_background_advertisement */); |
| sequence_number = |
| manager_->SendMessage(test_devices_[3].GetDeviceId(), "request3"); |
| VerifyLastMessageSent(channel3, sequence_number, "request3", 1); |
| |
| channel3->ReceiveMessage(kTetherFeature, "response3"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[3].GetDeviceId(), "response3"}}); |
| |
| // Assume that none of the other devices can connect, and unregister the |
| // remaining 3 devices. |
| manager_->UnregisterRemoteDevice(test_devices_[3].GetDeviceId(), |
| request_id_4); |
| VerifyDeviceNotRegistered(test_devices_[3]); |
| manager_->UnregisterRemoteDevice(test_devices_[1].GetDeviceId(), |
| request_id_2); |
| VerifyDeviceNotRegistered(test_devices_[1]); |
| manager_->UnregisterRemoteDevice(test_devices_[2].GetDeviceId(), |
| request_id_3); |
| VerifyDeviceNotRegistered(test_devices_[2]); |
| |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[3].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}, |
| {test_devices_[1].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}, |
| {test_devices_[2].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| fake_secure_channel_factory_->created_channels()[1]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[3].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| } |
| |
| // Regression test for crbug.com/733360. This bug caused a crash when there were |
| // multiple observers of BleConnectionManager. The bug was that when an event |
| // occurred which triggered observers to be notified (i.e., a status changed or |
| // message received event), sometimes one of the observers would unregister the |
| // device, which, in turn, caused the associated ConnectionMetadata to be |
| // deleted. Then, the next observer would be notified of the event after the |
| // deletion. Since the parameters to the observer callbacks were passed by |
| // reference (and the reference was held by the deleted ConnectionMetadata), |
| // this led to the second observer referencing deleted memory. The fix is to |
| // pass the parameters from the ConnectionMetadata to BleConnectionManager by |
| // value instead. |
| TEST_F(BleConnectionManagerTest, ObserverUnregisters) { |
| base::UnguessableToken request_id = base::UnguessableToken::Create(); |
| |
| FakeSecureChannelConnection* channel = |
| ConnectSuccessfully(test_devices_[0], kBluetoothAddress1, request_id, |
| false /* is_background_advertisement */); |
| |
| // Register two separate UnregisteringObservers. When a message is received, |
| // the first observer will unregister the device. |
| UnregisteringObserver first(manager_.get(), request_id); |
| UnregisteringObserver second(manager_.get(), request_id); |
| manager_->AddObserver(&first); |
| manager_->AddObserver(&second); |
| |
| // Receive a message over the channel. This should invoke the observer |
| // callbacks. This would have caused a crash before the fix for |
| // crbug.com/733360. |
| channel->ReceiveMessage(kTetherFeature, "response1"); |
| VerifyReceivedMessages(std::vector<ReceivedMessage>{ |
| {test_devices_[0].GetDeviceId(), "response1"}}); |
| // We expect the device to be unregistered (by the observer). |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::AUTHENTICATED, |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}}); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| |
| fake_secure_channel_factory_->created_channels()[0]->ChangeStatus( |
| secure_channel::SecureChannel::Status::DISCONNECTED); |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| |
| // Now, register the device again. This should cause a "disconnected => |
| // connecting" status change. This time, the multiple observers will respond |
| // to a status change event instead of a message received event. This also |
| // would have caused a crash before the fix for crbug.com/733360. |
| manager_->RegisterRemoteDevice(test_devices_[0].GetDeviceId(), request_id, |
| secure_channel::ConnectionPriority::kLow); |
| |
| // We expect the device to be unregistered (by the observer). |
| VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{ |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| secure_channel::SecureChannel::Status::CONNECTING, |
| BleConnectionManager::StateChangeDetail::STATE_CHANGE_DETAIL_NONE}, |
| {test_devices_[0].GetDeviceId(), |
| secure_channel::SecureChannel::Status::CONNECTING, |
| secure_channel::SecureChannel::Status::DISCONNECTED, |
| BleConnectionManager::StateChangeDetail:: |
| STATE_CHANGE_DETAIL_DEVICE_WAS_UNREGISTERED}}); |
| VerifyDeviceNotRegistered(test_devices_[0]); |
| } |
| |
| } // namespace tether |
| |
| } // namespace chromeos |