1// Copyright 2014 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/bluetooth_connection.h" 6 7#include "base/message_loop/message_loop.h" 8#include "base/numerics/safe_conversions.h" 9#include "base/run_loop.h" 10#include "components/proximity_auth/remote_device.h" 11#include "components/proximity_auth/wire_message.h" 12#include "device/bluetooth/bluetooth_adapter_factory.h" 13#include "device/bluetooth/bluetooth_uuid.h" 14#include "device/bluetooth/test/mock_bluetooth_adapter.h" 15#include "device/bluetooth/test/mock_bluetooth_device.h" 16#include "device/bluetooth/test/mock_bluetooth_socket.h" 17#include "net/base/io_buffer.h" 18#include "testing/gmock/include/gmock/gmock.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21using testing::_; 22using testing::AnyNumber; 23using testing::NiceMock; 24using testing::Ref; 25using testing::Return; 26using testing::SaveArg; 27using testing::StrictMock; 28 29namespace proximity_auth { 30namespace { 31 32const char kDeviceName[] = "Device name"; 33const char kOtherDeviceName[] = "Other device name"; 34 35const char kBluetoothAddress[] = "11:22:33:44:55:66"; 36const char kOtherBluetoothAddress[] = "AA:BB:CC:DD:EE:FF"; 37 38const char kSerializedMessage[] = "Yarrr, this be a serialized message. Yarr!"; 39const int kSerializedMessageLength = strlen(kSerializedMessage); 40 41const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF"; 42 43const RemoteDevice kRemoteDevice = {kDeviceName, kBluetoothAddress}; 44 45const int kReceiveBufferSize = 6; 46const char kReceiveBufferContents[] = "bytes"; 47 48// Create a buffer for testing received data. 49scoped_refptr<net::IOBuffer> CreateReceiveBuffer() { 50 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kReceiveBufferSize); 51 memcpy(buffer->data(), kReceiveBufferContents, kReceiveBufferSize); 52 return buffer; 53} 54 55class MockBluetoothConnection : public BluetoothConnection { 56 public: 57 MockBluetoothConnection() 58 : BluetoothConnection(kRemoteDevice, device::BluetoothUUID(kUuid)) {} 59 60 // Bluetooth dependencies. 61 typedef device::BluetoothDevice::ConnectToServiceCallback 62 ConnectToServiceCallback; 63 typedef device::BluetoothDevice::ConnectToServiceErrorCallback 64 ConnectToServiceErrorCallback; 65 MOCK_METHOD4(ConnectToService, 66 void(device::BluetoothDevice* device, 67 const device::BluetoothUUID& uuid, 68 const ConnectToServiceCallback& callback, 69 const ConnectToServiceErrorCallback& error_callback)); 70 71 // Calls back into the parent Connection class. 72 MOCK_METHOD1(SetStatusProxy, void(Status status)); 73 MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes)); 74 MOCK_METHOD2(OnDidSendMessage, 75 void(const WireMessage& message, bool success)); 76 77 virtual void SetStatus(Status status) OVERRIDE { 78 SetStatusProxy(status); 79 BluetoothConnection::SetStatus(status); 80 } 81 82 using BluetoothConnection::status; 83 using BluetoothConnection::Connect; 84 using BluetoothConnection::DeviceRemoved; 85 using BluetoothConnection::Disconnect; 86 87 private: 88 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection); 89}; 90 91class TestWireMessage : public WireMessage { 92 public: 93 TestWireMessage() : WireMessage("permit id", "payload") {} 94 virtual ~TestWireMessage() {} 95 96 virtual std::string Serialize() const OVERRIDE { return kSerializedMessage; } 97 98 private: 99 DISALLOW_COPY_AND_ASSIGN(TestWireMessage); 100}; 101 102} // namespace 103 104class ProximityAuthBluetoothConnectionTest : public testing::Test { 105 public: 106 ProximityAuthBluetoothConnectionTest() 107 : adapter_(new device::MockBluetoothAdapter), 108 device_(adapter_.get(), 0, kDeviceName, kBluetoothAddress, true, true), 109 socket_(new StrictMock<device::MockBluetoothSocket>), 110 uuid_(kUuid) { 111 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); 112 113 // Suppress uninteresting Gmock call warnings. 114 EXPECT_CALL(*adapter_, GetDevice(_)).Times(AnyNumber()); 115 } 116 117 // Transition the connection into an in-progress state. 118 void BeginConnecting(MockBluetoothConnection* connection) { 119 EXPECT_EQ(Connection::DISCONNECTED, connection->status()); 120 121 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); 122 EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS)); 123 EXPECT_CALL(*adapter_, AddObserver(connection)); 124 EXPECT_CALL(*connection, ConnectToService(&device_, uuid_, _, _)); 125 connection->Connect(); 126 127 EXPECT_EQ(Connection::IN_PROGRESS, connection->status()); 128 } 129 130 // Transition the connection into a connected state. 131 // Saves the success and error callbacks passed into OnReceive(), which can be 132 // accessed via receive_callback() and receive_success_callback(). 133 void Connect(MockBluetoothConnection* connection) { 134 EXPECT_EQ(Connection::DISCONNECTED, connection->status()); 135 136 device::BluetoothDevice::ConnectToServiceCallback callback; 137 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); 138 EXPECT_CALL(*connection, SetStatusProxy(Connection::IN_PROGRESS)); 139 EXPECT_CALL(*adapter_, AddObserver(connection)); 140 EXPECT_CALL(*connection, ConnectToService(_, _, _, _)) 141 .WillOnce(SaveArg<2>(&callback)); 142 connection->Connect(); 143 ASSERT_FALSE(callback.is_null()); 144 145 EXPECT_CALL(*connection, SetStatusProxy(Connection::CONNECTED)); 146 EXPECT_CALL(*socket_, Receive(_, _, _)) 147 .WillOnce(DoAll(SaveArg<1>(&receive_callback_), 148 SaveArg<2>(&receive_error_callback_))); 149 callback.Run(socket_); 150 151 EXPECT_EQ(Connection::CONNECTED, connection->status()); 152 } 153 154 device::BluetoothSocket::ReceiveCompletionCallback* receive_callback() { 155 return &receive_callback_; 156 } 157 device::BluetoothSocket::ReceiveErrorCompletionCallback* 158 receive_error_callback() { 159 return &receive_error_callback_; 160 } 161 162 protected: 163 // Mocks used for verifying interactions with the Bluetooth subsystem. 164 scoped_refptr<device::MockBluetoothAdapter> adapter_; 165 NiceMock<device::MockBluetoothDevice> device_; 166 scoped_refptr<StrictMock<device::MockBluetoothSocket>> socket_; 167 168 device::BluetoothUUID uuid_; 169 170 private: 171 base::MessageLoop message_loop_; 172 173 device::BluetoothSocket::ReceiveCompletionCallback receive_callback_; 174 device::BluetoothSocket::ReceiveErrorCompletionCallback 175 receive_error_callback_; 176}; 177 178TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasInProgress) { 179 // Create an in-progress connection. 180 StrictMock<MockBluetoothConnection> connection; 181 BeginConnecting(&connection); 182 183 // A second call to Connect() should be ignored. 184 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 185 connection.Connect(); 186 187 // The connection cleans up after itself upon destruction. 188 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 189} 190 191TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasConnected) { 192 // Create a connected connection. 193 StrictMock<MockBluetoothConnection> connection; 194 Connect(&connection); 195 196 // A second call to Connect() should be ignored. 197 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 198 connection.Connect(); 199 200 // The connection disconnects and unregisters as an observer upon destruction. 201 EXPECT_CALL(*socket_, Disconnect(_)); 202 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 203} 204 205TEST_F(ProximityAuthBluetoothConnectionTest, Connect_NoBluetoothAdapter) { 206 // Some platforms do not support Bluetooth. This test is only meaningful on 207 // those platforms. 208 adapter_ = NULL; 209 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) 210 return; 211 212 StrictMock<MockBluetoothConnection> connection; 213 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 214 connection.Connect(); 215} 216 217TEST_F(ProximityAuthBluetoothConnectionTest, Connect_DeviceMissing) { 218 StrictMock<MockBluetoothConnection> connection; 219 220 ON_CALL(*adapter_, GetDevice(_)) 221 .WillByDefault(Return(static_cast<device::BluetoothDevice*>(NULL))); 222 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); 223 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 224 connection.Connect(); 225} 226 227TEST_F(ProximityAuthBluetoothConnectionTest, 228 Connect_DeviceRemovedWhileConnecting) { 229 // Create an in-progress connection. 230 StrictMock<MockBluetoothConnection> connection; 231 BeginConnecting(&connection); 232 233 // Remove the device while the connection is in-progress. This should cause 234 // the connection to disconnect. 235 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 236 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 237 connection.DeviceRemoved(adapter_.get(), &device_); 238} 239 240TEST_F(ProximityAuthBluetoothConnectionTest, 241 Connect_OtherDeviceRemovedWhileConnecting) { 242 // Create an in-progress connection. 243 StrictMock<MockBluetoothConnection> connection; 244 BeginConnecting(&connection); 245 246 // Remove a device other than the one that is being connected to. This should 247 // not have any effect on the connection. 248 NiceMock<device::MockBluetoothDevice> other_device( 249 adapter_.get(), 0, kOtherDeviceName, kOtherBluetoothAddress, true, true); 250 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 251 connection.DeviceRemoved(adapter_.get(), &other_device); 252 253 // The connection removes itself as an observer when it is destroyed. 254 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 255} 256 257TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionFails) { 258 StrictMock<MockBluetoothConnection> connection; 259 260 device::BluetoothDevice::ConnectToServiceErrorCallback error_callback; 261 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); 262 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); 263 EXPECT_CALL(*adapter_, AddObserver(&connection)); 264 EXPECT_CALL(connection, ConnectToService(&device_, uuid_, _, _)) 265 .WillOnce(SaveArg<3>(&error_callback)); 266 connection.Connect(); 267 ASSERT_FALSE(error_callback.is_null()); 268 269 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 270 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 271 error_callback.Run("super descriptive error message"); 272} 273 274TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionSucceeds) { 275 StrictMock<MockBluetoothConnection> connection; 276 Connect(&connection); 277 278 // The connection disconnects and unregisters as an observer upon destruction. 279 EXPECT_CALL(*socket_, Disconnect(_)); 280 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 281} 282 283TEST_F(ProximityAuthBluetoothConnectionTest, 284 Connect_ConnectionSucceeds_ThenDeviceRemoved) { 285 StrictMock<MockBluetoothConnection> connection; 286 Connect(&connection); 287 288 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 289 EXPECT_CALL(*socket_, Disconnect(_)); 290 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 291 connection.DeviceRemoved(adapter_.get(), &device_); 292} 293 294TEST_F(ProximityAuthBluetoothConnectionTest, 295 Connect_ConnectionSucceeds_ReceiveData) { 296 StrictMock<MockBluetoothConnection> connection; 297 Connect(&connection); 298 ASSERT_TRUE(receive_callback() && !receive_callback()->is_null()); 299 300 // Receive some data. Once complete, the connection should re-register to be 301 // ready receive more data. 302 scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer(); 303 EXPECT_CALL( 304 connection, 305 OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize))); 306 EXPECT_CALL(*socket_, Receive(_, _, _)); 307 receive_callback()->Run(kReceiveBufferSize, buffer); 308 base::RunLoop run_loop; 309 run_loop.RunUntilIdle(); 310 311 // The connection disconnects and unregisters as an observer upon destruction. 312 EXPECT_CALL(*socket_, Disconnect(_)); 313 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 314} 315 316TEST_F(ProximityAuthBluetoothConnectionTest, 317 Connect_ConnectionSucceeds_ReceiveDataAfterReceiveError) { 318 StrictMock<MockBluetoothConnection> connection; 319 Connect(&connection); 320 ASSERT_TRUE(receive_error_callback() && !receive_error_callback()->is_null()); 321 322 // Simulate an error while receiving data. The connection should re-register 323 // to be ready receive more data despite the error. 324 device::BluetoothSocket::ReceiveCompletionCallback receive_callback; 325 EXPECT_CALL(*socket_, Receive(_, _, _)) 326 .WillOnce(SaveArg<1>(&receive_callback)); 327 receive_error_callback()->Run(device::BluetoothSocket::kSystemError, 328 "The system is down. They're taking over!"); 329 base::RunLoop run_loop; 330 run_loop.RunUntilIdle(); 331 ASSERT_FALSE(receive_callback.is_null()); 332 333 // Receive some data. 334 scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer(); 335 EXPECT_CALL( 336 connection, 337 OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize))); 338 EXPECT_CALL(*socket_, Receive(_, _, _)); 339 receive_callback.Run(kReceiveBufferSize, buffer); 340 base::RunLoop run_loop2; 341 run_loop2.RunUntilIdle(); 342 343 // The connection disconnects and unregisters as an observer upon destruction. 344 EXPECT_CALL(*socket_, Disconnect(_)); 345 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 346} 347 348TEST_F(ProximityAuthBluetoothConnectionTest, 349 Disconnect_ConnectionWasAlreadyDisconnected) { 350 StrictMock<MockBluetoothConnection> connection; 351 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 352 connection.Disconnect(); 353} 354 355TEST_F(ProximityAuthBluetoothConnectionTest, 356 Disconnect_ConnectionWasInProgress) { 357 // Create an in-progress connection. 358 StrictMock<MockBluetoothConnection> connection; 359 BeginConnecting(&connection); 360 361 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 362 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 363 connection.Disconnect(); 364} 365 366TEST_F(ProximityAuthBluetoothConnectionTest, 367 Disconnect_ConnectionWasConnected) { 368 // Create a connected connection. 369 StrictMock<MockBluetoothConnection> connection; 370 Connect(&connection); 371 372 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 373 EXPECT_CALL(*socket_, Disconnect(_)); 374 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 375 connection.Disconnect(); 376} 377 378TEST_F(ProximityAuthBluetoothConnectionTest, 379 Connect_ThenDisconnectWhileInProgress_ThenBackingConnectionSucceeds) { 380 StrictMock<MockBluetoothConnection> connection; 381 device::BluetoothDevice::ConnectToServiceCallback callback; 382 ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_)); 383 EXPECT_CALL(connection, SetStatusProxy(Connection::IN_PROGRESS)); 384 EXPECT_CALL(*adapter_, AddObserver(&connection)); 385 EXPECT_CALL(connection, ConnectToService(&device_, uuid_, _, _)) 386 .WillOnce(SaveArg<2>(&callback)); 387 connection.Connect(); 388 ASSERT_FALSE(callback.is_null()); 389 390 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 391 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 392 connection.Disconnect(); 393 394 EXPECT_CALL(connection, SetStatusProxy(_)).Times(0); 395 EXPECT_CALL(*socket_, Receive(_, _, _)).Times(0); 396 callback.Run(socket_); 397} 398 399TEST_F(ProximityAuthBluetoothConnectionTest, 400 SendMessage_SendsExpectedDataOverTheWire) { 401 // Create a connected connection. 402 StrictMock<MockBluetoothConnection> connection; 403 Connect(&connection); 404 405 scoped_refptr<net::IOBuffer> buffer; 406 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); 407 EXPECT_CALL(*socket_, Send(_, kSerializedMessageLength, _, _)) 408 .WillOnce(SaveArg<0>(&buffer)); 409 connection.SendMessage(wire_message.PassAs<WireMessage>()); 410 ASSERT_TRUE(buffer.get()); 411 EXPECT_EQ(kSerializedMessage, 412 std::string(buffer->data(), kSerializedMessageLength)); 413 414 // The connection disconnects and unregisters as an observer upon destruction. 415 EXPECT_CALL(*socket_, Disconnect(_)); 416 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 417} 418 419TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Success) { 420 // Create a connected connection. 421 StrictMock<MockBluetoothConnection> connection; 422 Connect(&connection); 423 424 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); 425 // Ownership will be transfered below, so grab a reference here. 426 TestWireMessage* expected_wire_message = wire_message.get(); 427 428 device::BluetoothSocket::SendCompletionCallback callback; 429 EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<2>(&callback)); 430 connection.SendMessage(wire_message.PassAs<WireMessage>()); 431 ASSERT_FALSE(callback.is_null()); 432 433 EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), true)); 434 callback.Run(kSerializedMessageLength); 435 436 // The connection disconnects and unregisters as an observer upon destruction. 437 EXPECT_CALL(*socket_, Disconnect(_)); 438 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 439} 440 441TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Failure) { 442 // Create a connected connection. 443 StrictMock<MockBluetoothConnection> connection; 444 Connect(&connection); 445 446 scoped_ptr<TestWireMessage> wire_message(new TestWireMessage); 447 // Ownership will be transfered below, so grab a reference here. 448 TestWireMessage* expected_wire_message = wire_message.get(); 449 450 device::BluetoothSocket::ErrorCompletionCallback error_callback; 451 EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<3>(&error_callback)); 452 connection.SendMessage(wire_message.PassAs<WireMessage>()); 453 454 ASSERT_FALSE(error_callback.is_null()); 455 EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), false)); 456 EXPECT_CALL(connection, SetStatusProxy(Connection::DISCONNECTED)); 457 EXPECT_CALL(*socket_, Disconnect(_)); 458 EXPECT_CALL(*adapter_, RemoveObserver(&connection)); 459 error_callback.Run("The most helpful of error messages"); 460} 461 462} // namespace proximity_auth 463