OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h
" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/time/time.h" |
| 11 #include "components/proximity_auth/connection.h" |
| 12 #include "components/proximity_auth/remote_device.h" |
| 13 #include "components/proximity_auth/wire_message.h" |
| 14 #include "device/bluetooth/bluetooth_adapter_factory.h" |
| 15 #include "device/bluetooth/bluetooth_uuid.h" |
| 16 #include "device/bluetooth/test/mock_bluetooth_adapter.h" |
| 17 #include "device/bluetooth/test/mock_bluetooth_device.h" |
| 18 #include "device/bluetooth/test/mock_bluetooth_discovery_session.h" |
| 19 #include "device/bluetooth/test/mock_bluetooth_gatt_connection.h" |
| 20 #include "testing/gmock/include/gmock/gmock.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 |
| 23 using testing::_; |
| 24 using testing::AtLeast; |
| 25 using testing::NiceMock; |
| 26 using testing::Return; |
| 27 using testing::StrictMock; |
| 28 using testing::SaveArg; |
| 29 |
| 30 namespace proximity_auth { |
| 31 namespace { |
| 32 |
| 33 const char kDeviceName[] = "Device name"; |
| 34 const char kBluetoothAddress[] = "11:22:33:44:55:66"; |
| 35 const RemoteDevice kRemoteDevice = {kDeviceName, kBluetoothAddress}; |
| 36 |
| 37 const char kServiceUUID[] = "1EADBEEF-CAFE-FEED-FOOD-D15EA5EBEEEF"; |
| 38 const char kToPeripheralCharUUID[] = "2EADBEEF-CAFE-FEED-FOOD-D15EA5EBEEEF"; |
| 39 const char kFromPeripheralCharUUID[] = "3EADBEEF-CAFE-FEED-FOOD-D15EA5EBEEEF"; |
| 40 |
| 41 const char kOtherUUID[] = "AAAAAAAA-AAAA-AAAA-AAAA-D15EA5EBEEEF"; |
| 42 const char kOtherBluetoothAddress[] = "00:00:00:00:00:00"; |
| 43 |
| 44 class MockConnection : public Connection { |
| 45 public: |
| 46 MockConnection() : Connection(kRemoteDevice) {} |
| 47 ~MockConnection() override {} |
| 48 |
| 49 MOCK_METHOD0(Connect, void()); |
| 50 |
| 51 using Connection::SetStatus; |
| 52 |
| 53 private: |
| 54 void Disconnect() override {} |
| 55 void SendMessageImpl(scoped_ptr<WireMessage> message) override {} |
| 56 |
| 57 DISALLOW_COPY_AND_ASSIGN(MockConnection); |
| 58 }; |
| 59 |
| 60 class MockBluetoothLowEnergyConnectionFinder |
| 61 : public BluetoothLowEnergyConnectionFinder { |
| 62 public: |
| 63 MockBluetoothLowEnergyConnectionFinder() |
| 64 : BluetoothLowEnergyConnectionFinder(kServiceUUID, |
| 65 kToPeripheralCharUUID, |
| 66 kFromPeripheralCharUUID) {} |
| 67 ~MockBluetoothLowEnergyConnectionFinder() override {} |
| 68 |
| 69 // Mock methods don't support return type scoped_ptr<>. This is a possible |
| 70 // workaround: mock a proxy method to be called by the target overrided method |
| 71 // (CreateConnection). |
| 72 MOCK_METHOD0(CreateConnectionProxy, Connection*()); |
| 73 |
| 74 // Creates a mock connection and sets an expectation that the mock connection |
| 75 // finder's CreateConnection() method will be called and will return the |
| 76 // created connection. Returns a reference to the created connection. |
| 77 // NOTE: The returned connection's lifetime is managed by the connection |
| 78 // finder. |
| 79 MockConnection* ExpectCreateConnection() { |
| 80 scoped_ptr<MockConnection> connection(new NiceMock<MockConnection>()); |
| 81 MockConnection* connection_alias = connection.get(); |
| 82 EXPECT_CALL(*this, CreateConnectionProxy()) |
| 83 .WillOnce(Return(connection.release())); |
| 84 return connection_alias; |
| 85 } |
| 86 |
| 87 protected: |
| 88 scoped_ptr<Connection> CreateConnection( |
| 89 scoped_ptr<device::BluetoothGattConnection> gatt_connection) override { |
| 90 return make_scoped_ptr(CreateConnectionProxy()); |
| 91 } |
| 92 |
| 93 private: |
| 94 DISALLOW_COPY_AND_ASSIGN(MockBluetoothLowEnergyConnectionFinder); |
| 95 }; |
| 96 |
| 97 } // namespace |
| 98 |
| 99 class ProximityAuthBluetoothLowEnergyConnectionFinderTest |
| 100 : public testing::Test { |
| 101 protected: |
| 102 ProximityAuthBluetoothLowEnergyConnectionFinderTest() |
| 103 : adapter_(new NiceMock<device::MockBluetoothAdapter>), |
| 104 connection_callback_( |
| 105 base::Bind(&ProximityAuthBluetoothLowEnergyConnectionFinderTest:: |
| 106 OnConnectionFound, |
| 107 base::Unretained(this))), |
| 108 device_(new NiceMock<device::MockBluetoothDevice>(adapter_.get(), |
| 109 0, |
| 110 kDeviceName, |
| 111 kBluetoothAddress, |
| 112 false, |
| 113 false)) { |
| 114 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); |
| 115 |
| 116 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true)); |
| 117 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true)); |
| 118 } |
| 119 |
| 120 void OnConnectionFound(scoped_ptr<Connection> connection) { |
| 121 last_found_connection_ = connection.Pass(); |
| 122 } |
| 123 |
| 124 void FindAndExpectStartDiscovery( |
| 125 BluetoothLowEnergyConnectionFinder& connection_finder) { |
| 126 device::BluetoothAdapter::DiscoverySessionCallback discovery_callback; |
| 127 scoped_ptr<device::MockBluetoothDiscoverySession> discovery_session( |
| 128 new NiceMock<device::MockBluetoothDiscoverySession>()); |
| 129 device::MockBluetoothDiscoverySession* discovery_session_alias = |
| 130 discovery_session.get(); |
| 131 |
| 132 // Starting a discovery session |
| 133 EXPECT_CALL(*adapter_, StartDiscoverySession(_, _)) |
| 134 .WillOnce(SaveArg<0>(&discovery_callback)); |
| 135 EXPECT_CALL(*adapter_, AddObserver(_)); |
| 136 ON_CALL(*discovery_session_alias, IsActive()).WillByDefault(Return(true)); |
| 137 connection_finder.Find(connection_callback_); |
| 138 ASSERT_FALSE(discovery_callback.is_null()); |
| 139 discovery_callback.Run(discovery_session.Pass()); |
| 140 |
| 141 // Cleaning up |
| 142 EXPECT_CALL(*discovery_session_alias, Stop(_, _)).Times(AtLeast(1)); |
| 143 EXPECT_CALL(*adapter_, RemoveObserver(_)); |
| 144 } |
| 145 |
| 146 // Prepare |device_| with |uuid|. |
| 147 void PrepareDevice(const std::string& uuid) { |
| 148 std::vector<device::BluetoothUUID> uuids; |
| 149 uuids.push_back(device::BluetoothUUID(uuid)); |
| 150 ON_CALL(*device_, GetUUIDs()).WillByDefault(Return(uuids)); |
| 151 } |
| 152 |
| 153 // Prepare expectations to add/change a right device. |
| 154 void PrepareForNewRightDevice( |
| 155 const std::string& uuid, |
| 156 device::BluetoothDevice::GattConnectionCallback& callback) { |
| 157 PrepareDevice(uuid); |
| 158 EXPECT_CALL(*device_, CreateGattConnection(_, _)) |
| 159 .WillOnce(SaveArg<0>(&callback)); |
| 160 } |
| 161 |
| 162 // Prepare expectations to add/change a wrong device. |
| 163 void PrepareForNewWrongDevice(const std::string& uuid) { |
| 164 PrepareDevice(uuid); |
| 165 EXPECT_CALL(*device_, CreateGattConnection(_, _)).Times(0); |
| 166 } |
| 167 |
| 168 scoped_refptr<device::MockBluetoothAdapter> adapter_; |
| 169 ConnectionFinder::ConnectionCallback connection_callback_; |
| 170 |
| 171 protected: |
| 172 scoped_ptr<device::MockBluetoothDevice> device_; |
| 173 scoped_ptr<Connection> last_found_connection_; |
| 174 }; |
| 175 |
| 176 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 177 ConstructAndDestroyDoesntCrash) { |
| 178 // Destroying a BluetoothConnectionFinder for which Find() has not been called |
| 179 // should not crash. |
| 180 BluetoothLowEnergyConnectionFinder connection_finder( |
| 181 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 182 } |
| 183 |
| 184 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 185 Find_StartsDiscoverySession) { |
| 186 BluetoothLowEnergyConnectionFinder connection_finder( |
| 187 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 188 |
| 189 EXPECT_CALL(*adapter_, StartDiscoverySession(_, _)); |
| 190 EXPECT_CALL(*adapter_, AddObserver(_)); |
| 191 connection_finder.Find(connection_callback_); |
| 192 } |
| 193 |
| 194 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 195 Find_StopsDiscoverySessionBeforeDestroying) { |
| 196 BluetoothLowEnergyConnectionFinder connection_finder( |
| 197 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 198 |
| 199 device::BluetoothAdapter::DiscoverySessionCallback discovery_callback; |
| 200 scoped_ptr<device::MockBluetoothDiscoverySession> discovery_session( |
| 201 new NiceMock<device::MockBluetoothDiscoverySession>()); |
| 202 device::MockBluetoothDiscoverySession* discovery_session_alias = |
| 203 discovery_session.get(); |
| 204 |
| 205 EXPECT_CALL(*adapter_, StartDiscoverySession(_, _)) |
| 206 .WillOnce(SaveArg<0>(&discovery_callback)); |
| 207 ON_CALL(*discovery_session_alias, IsActive()).WillByDefault(Return(true)); |
| 208 EXPECT_CALL(*adapter_, AddObserver(_)); |
| 209 connection_finder.Find(connection_callback_); |
| 210 |
| 211 EXPECT_CALL(*discovery_session_alias, Stop(_, _)); |
| 212 ASSERT_FALSE(discovery_callback.is_null()); |
| 213 discovery_callback.Run(discovery_session.Pass()); |
| 214 |
| 215 EXPECT_CALL(*adapter_, RemoveObserver(_)); |
| 216 } |
| 217 |
| 218 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 219 Find_CreatesGattConnectionWhenRightDeviceIsAdded) { |
| 220 BluetoothLowEnergyConnectionFinder connection_finder( |
| 221 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 222 device::BluetoothDevice::GattConnectionCallback gatt_connection_callback; |
| 223 FindAndExpectStartDiscovery(connection_finder); |
| 224 |
| 225 PrepareForNewRightDevice(kServiceUUID, gatt_connection_callback); |
| 226 connection_finder.DeviceAdded(adapter_.get(), device_.get()); |
| 227 ASSERT_FALSE(gatt_connection_callback.is_null()); |
| 228 } |
| 229 |
| 230 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 231 Find_DoesntCreateGattConnectionWhenWrongDeviceIsAdded) { |
| 232 BluetoothLowEnergyConnectionFinder connection_finder( |
| 233 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 234 FindAndExpectStartDiscovery(connection_finder); |
| 235 |
| 236 PrepareForNewWrongDevice(kOtherUUID); |
| 237 connection_finder.DeviceAdded(adapter_.get(), device_.get()); |
| 238 } |
| 239 |
| 240 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 241 Find_CreatesGattConnectionWhenRightDeviceIsChanged) { |
| 242 BluetoothLowEnergyConnectionFinder connection_finder( |
| 243 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 244 device::BluetoothDevice::GattConnectionCallback gatt_connection_callback; |
| 245 FindAndExpectStartDiscovery(connection_finder); |
| 246 |
| 247 PrepareForNewRightDevice(kServiceUUID, gatt_connection_callback); |
| 248 connection_finder.DeviceChanged(adapter_.get(), device_.get()); |
| 249 ASSERT_FALSE(gatt_connection_callback.is_null()); |
| 250 } |
| 251 |
| 252 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 253 Find_DoesntCreateGattConnectionWhenWrongDeviceIsChanged) { |
| 254 BluetoothLowEnergyConnectionFinder connection_finder( |
| 255 kServiceUUID, kToPeripheralCharUUID, kFromPeripheralCharUUID); |
| 256 FindAndExpectStartDiscovery(connection_finder); |
| 257 |
| 258 PrepareForNewWrongDevice(kOtherUUID); |
| 259 connection_finder.DeviceChanged(adapter_.get(), device_.get()); |
| 260 } |
| 261 |
| 262 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 263 Find_CreatesTwoGattConnections) { |
| 264 StrictMock<MockBluetoothLowEnergyConnectionFinder> connection_finder; |
| 265 FindAndExpectStartDiscovery(connection_finder); |
| 266 connection_finder.ExpectCreateConnection(); |
| 267 |
| 268 // Prepare to add |device_|. |
| 269 device::BluetoothDevice::GattConnectionCallback gatt_connection_callback; |
| 270 PrepareForNewRightDevice(kServiceUUID, gatt_connection_callback); |
| 271 |
| 272 // Prepare to add |other_device|. |
| 273 device::BluetoothDevice::GattConnectionCallback |
| 274 other_gatt_connection_callback; |
| 275 NiceMock<device::MockBluetoothDevice> other_device( |
| 276 adapter_.get(), 0, kDeviceName, kOtherBluetoothAddress, false, false); |
| 277 std::vector<device::BluetoothUUID> uuids; |
| 278 uuids.push_back(device::BluetoothUUID(kServiceUUID)); |
| 279 ON_CALL(other_device, GetUUIDs()).WillByDefault((Return(uuids))); |
| 280 EXPECT_CALL(other_device, CreateGattConnection(_, _)) |
| 281 .WillOnce(SaveArg<0>(&other_gatt_connection_callback)); |
| 282 |
| 283 // Add the devices. |
| 284 connection_finder.DeviceAdded(adapter_.get(), device_.get()); |
| 285 connection_finder.DeviceAdded(adapter_.get(), &other_device); |
| 286 |
| 287 ASSERT_FALSE(gatt_connection_callback.is_null()); |
| 288 ASSERT_FALSE(other_gatt_connection_callback.is_null()); |
| 289 |
| 290 gatt_connection_callback.Run(make_scoped_ptr( |
| 291 new NiceMock<device::MockBluetoothGattConnection>(kBluetoothAddress))); |
| 292 |
| 293 // The second device should be forgetten |
| 294 EXPECT_CALL(*adapter_, GetDevice(std::string(kOtherBluetoothAddress))) |
| 295 .WillOnce(Return(&other_device)); |
| 296 EXPECT_CALL(other_device, Forget(_)); |
| 297 other_gatt_connection_callback.Run( |
| 298 make_scoped_ptr(new NiceMock<device::MockBluetoothGattConnection>( |
| 299 kOtherBluetoothAddress))); |
| 300 } |
| 301 |
| 302 TEST_F(ProximityAuthBluetoothLowEnergyConnectionFinderTest, |
| 303 Find_ConnectionSucceeds) { |
| 304 StrictMock<MockBluetoothLowEnergyConnectionFinder> connection_finder; |
| 305 |
| 306 // Starting discovery |
| 307 FindAndExpectStartDiscovery(connection_finder); |
| 308 |
| 309 // Finding and creating a GATT connection to the right device |
| 310 device::BluetoothDevice::GattConnectionCallback gatt_connection_callback; |
| 311 PrepareForNewRightDevice(kServiceUUID, gatt_connection_callback); |
| 312 connection_finder.DeviceAdded(adapter_.get(), device_.get()); |
| 313 |
| 314 // Creating a connection |
| 315 MockConnection* connection = connection_finder.ExpectCreateConnection(); |
| 316 ASSERT_FALSE(gatt_connection_callback.is_null()); |
| 317 gatt_connection_callback.Run(make_scoped_ptr( |
| 318 new NiceMock<device::MockBluetoothGattConnection>(kBluetoothAddress))); |
| 319 ASSERT_FALSE(last_found_connection_); |
| 320 connection->SetStatus(Connection::IN_PROGRESS); |
| 321 connection->SetStatus(Connection::CONNECTED); |
| 322 ASSERT_FALSE(!last_found_connection_); |
| 323 } |
| 324 |
| 325 } // namespace proximity_auth |
OLD | NEW |