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.
5 #include "components/proximity_auth/bluetooth_connection.h"
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"
22 using testing::AnyNumber
;
23 using testing::NiceMock
;
25 using testing::Return
;
26 using testing::SaveArg
;
27 using testing::StrictMock
;
29 namespace proximity_auth
{
32 const char kDeviceName
[] = "Device name";
33 const char kOtherDeviceName
[] = "Other device name";
35 const char kBluetoothAddress
[] = "11:22:33:44:55:66";
36 const char kOtherBluetoothAddress
[] = "AA:BB:CC:DD:EE:FF";
38 const char kPublicKey
[] = "Public key";
39 const char kPersistentSymmetricKey
[] = "PSK";
41 const char kSerializedMessage
[] = "Yarrr, this be a serialized message. Yarr!";
42 const int kSerializedMessageLength
= strlen(kSerializedMessage
);
44 const char kUuid
[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
46 const int kReceiveBufferSize
= 6;
47 const char kReceiveBufferContents
[] = "bytes";
49 // Create a buffer for testing received data.
50 scoped_refptr
<net::IOBuffer
> CreateReceiveBuffer() {
51 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(kReceiveBufferSize
);
52 memcpy(buffer
->data(), kReceiveBufferContents
, kReceiveBufferSize
);
56 class MockBluetoothConnection
: public BluetoothConnection
{
58 MockBluetoothConnection()
59 : BluetoothConnection(CreateRemoteDevice(),
60 device::BluetoothUUID(kUuid
)) {}
62 // Calls back into the parent Connection class.
63 MOCK_METHOD1(SetStatusProxy
, void(Status status
));
64 MOCK_METHOD1(OnBytesReceived
, void(const std::string
& bytes
));
65 MOCK_METHOD2(OnDidSendMessage
,
66 void(const WireMessage
& message
, bool success
));
68 void SetStatus(Status status
) override
{
69 SetStatusProxy(status
);
70 BluetoothConnection::SetStatus(status
);
73 using BluetoothConnection::status
;
74 using BluetoothConnection::Connect
;
75 using BluetoothConnection::DeviceRemoved
;
76 using BluetoothConnection::Disconnect
;
79 RemoteDevice
CreateRemoteDevice() {
80 return RemoteDevice(kDeviceName
, kPublicKey
, kBluetoothAddress
,
81 kPersistentSymmetricKey
);
84 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection
);
87 class TestWireMessage
: public WireMessage
{
89 TestWireMessage() : WireMessage("permit id", "payload") {}
90 ~TestWireMessage() override
{}
92 std::string
Serialize() const override
{ return kSerializedMessage
; }
95 DISALLOW_COPY_AND_ASSIGN(TestWireMessage
);
100 class ProximityAuthBluetoothConnectionTest
: public testing::Test
{
102 ProximityAuthBluetoothConnectionTest()
103 : adapter_(new device::MockBluetoothAdapter
),
104 device_(adapter_
.get(), 0, kDeviceName
, kBluetoothAddress
, true, true),
105 socket_(new StrictMock
<device::MockBluetoothSocket
>),
107 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_
);
109 // Suppress uninteresting Gmock call warnings.
110 EXPECT_CALL(*adapter_
, GetDevice(_
)).Times(AnyNumber());
113 // Transition the connection into an in-progress state.
114 void BeginConnecting(MockBluetoothConnection
* connection
) {
115 EXPECT_EQ(Connection::DISCONNECTED
, connection
->status());
117 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
118 EXPECT_CALL(*connection
, SetStatusProxy(Connection::IN_PROGRESS
));
119 EXPECT_CALL(*adapter_
, AddObserver(connection
));
120 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
));
121 connection
->Connect();
123 EXPECT_EQ(Connection::IN_PROGRESS
, connection
->status());
126 // Transition the connection into a connected state.
127 // Saves the success and error callbacks passed into OnReceive(), which can be
128 // accessed via receive_callback() and receive_success_callback().
129 void Connect(MockBluetoothConnection
* connection
) {
130 EXPECT_EQ(Connection::DISCONNECTED
, connection
->status());
132 device::BluetoothDevice::ConnectToServiceCallback callback
;
133 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
134 EXPECT_CALL(*connection
, SetStatusProxy(Connection::IN_PROGRESS
));
135 EXPECT_CALL(*adapter_
, AddObserver(connection
));
136 EXPECT_CALL(device_
, ConnectToServiceInsecurely(_
, _
, _
))
137 .WillOnce(SaveArg
<1>(&callback
));
138 connection
->Connect();
139 ASSERT_FALSE(callback
.is_null());
141 EXPECT_CALL(*connection
, SetStatusProxy(Connection::CONNECTED
));
142 EXPECT_CALL(*socket_
, Receive(_
, _
, _
))
143 .WillOnce(DoAll(SaveArg
<1>(&receive_callback_
),
144 SaveArg
<2>(&receive_error_callback_
)));
145 callback
.Run(socket_
);
147 EXPECT_EQ(Connection::CONNECTED
, connection
->status());
150 device::BluetoothSocket::ReceiveCompletionCallback
* receive_callback() {
151 return &receive_callback_
;
153 device::BluetoothSocket::ReceiveErrorCompletionCallback
*
154 receive_error_callback() {
155 return &receive_error_callback_
;
159 // Mocks used for verifying interactions with the Bluetooth subsystem.
160 scoped_refptr
<device::MockBluetoothAdapter
> adapter_
;
161 NiceMock
<device::MockBluetoothDevice
> device_
;
162 scoped_refptr
<StrictMock
<device::MockBluetoothSocket
>> socket_
;
164 device::BluetoothUUID uuid_
;
167 base::MessageLoop message_loop_
;
169 device::BluetoothSocket::ReceiveCompletionCallback receive_callback_
;
170 device::BluetoothSocket::ReceiveErrorCompletionCallback
171 receive_error_callback_
;
174 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionWasInProgress
) {
175 // Create an in-progress connection.
176 StrictMock
<MockBluetoothConnection
> connection
;
177 BeginConnecting(&connection
);
179 // A second call to Connect() should be ignored.
180 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
181 connection
.Connect();
183 // The connection cleans up after itself upon destruction.
184 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
187 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionWasConnected
) {
188 // Create a connected connection.
189 StrictMock
<MockBluetoothConnection
> connection
;
190 Connect(&connection
);
192 // A second call to Connect() should be ignored.
193 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
194 connection
.Connect();
196 // The connection disconnects and unregisters as an observer upon destruction.
197 EXPECT_CALL(*socket_
, Disconnect(_
));
198 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
201 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_NoBluetoothAdapter
) {
202 // Some platforms do not support Bluetooth. This test is only meaningful on
205 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
208 StrictMock
<MockBluetoothConnection
> connection
;
209 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
210 connection
.Connect();
213 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_DeviceMissing
) {
214 StrictMock
<MockBluetoothConnection
> connection
;
216 ON_CALL(*adapter_
, GetDevice(_
))
217 .WillByDefault(Return(static_cast<device::BluetoothDevice
*>(NULL
)));
218 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
219 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
220 connection
.Connect();
223 TEST_F(ProximityAuthBluetoothConnectionTest
,
224 Connect_DeviceRemovedWhileConnecting
) {
225 // Create an in-progress connection.
226 StrictMock
<MockBluetoothConnection
> connection
;
227 BeginConnecting(&connection
);
229 // Remove the device while the connection is in-progress. This should cause
230 // the connection to disconnect.
231 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
232 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
233 connection
.DeviceRemoved(adapter_
.get(), &device_
);
236 TEST_F(ProximityAuthBluetoothConnectionTest
,
237 Connect_OtherDeviceRemovedWhileConnecting
) {
238 // Create an in-progress connection.
239 StrictMock
<MockBluetoothConnection
> connection
;
240 BeginConnecting(&connection
);
242 // Remove a device other than the one that is being connected to. This should
243 // not have any effect on the connection.
244 NiceMock
<device::MockBluetoothDevice
> other_device(
245 adapter_
.get(), 0, kOtherDeviceName
, kOtherBluetoothAddress
, true, true);
246 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
247 connection
.DeviceRemoved(adapter_
.get(), &other_device
);
249 // The connection removes itself as an observer when it is destroyed.
250 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
253 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionFails
) {
254 StrictMock
<MockBluetoothConnection
> connection
;
256 device::BluetoothDevice::ConnectToServiceErrorCallback error_callback
;
257 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
258 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
259 EXPECT_CALL(*adapter_
, AddObserver(&connection
));
260 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
))
261 .WillOnce(SaveArg
<2>(&error_callback
));
262 connection
.Connect();
263 ASSERT_FALSE(error_callback
.is_null());
265 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
266 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
267 error_callback
.Run("super descriptive error message");
270 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionSucceeds
) {
271 StrictMock
<MockBluetoothConnection
> connection
;
272 Connect(&connection
);
274 // The connection disconnects and unregisters as an observer upon destruction.
275 EXPECT_CALL(*socket_
, Disconnect(_
));
276 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
279 TEST_F(ProximityAuthBluetoothConnectionTest
,
280 Connect_ConnectionSucceeds_ThenDeviceRemoved
) {
281 StrictMock
<MockBluetoothConnection
> connection
;
282 Connect(&connection
);
284 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
285 EXPECT_CALL(*socket_
, Disconnect(_
));
286 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
287 connection
.DeviceRemoved(adapter_
.get(), &device_
);
290 TEST_F(ProximityAuthBluetoothConnectionTest
,
291 Connect_ConnectionSucceeds_ReceiveData
) {
292 StrictMock
<MockBluetoothConnection
> connection
;
293 Connect(&connection
);
294 ASSERT_TRUE(receive_callback() && !receive_callback()->is_null());
296 // Receive some data. Once complete, the connection should re-register to be
297 // ready receive more data.
298 scoped_refptr
<net::IOBuffer
> buffer
= CreateReceiveBuffer();
301 OnBytesReceived(std::string(kReceiveBufferContents
, kReceiveBufferSize
)));
302 EXPECT_CALL(*socket_
, Receive(_
, _
, _
));
303 receive_callback()->Run(kReceiveBufferSize
, buffer
);
304 base::RunLoop run_loop
;
305 run_loop
.RunUntilIdle();
307 // The connection disconnects and unregisters as an observer upon destruction.
308 EXPECT_CALL(*socket_
, Disconnect(_
));
309 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
312 TEST_F(ProximityAuthBluetoothConnectionTest
,
313 Connect_ConnectionSucceeds_ReceiveDataAfterReceiveError
) {
314 StrictMock
<MockBluetoothConnection
> connection
;
315 Connect(&connection
);
316 ASSERT_TRUE(receive_error_callback() && !receive_error_callback()->is_null());
318 // Simulate an error while receiving data. The connection should re-register
319 // to be ready receive more data despite the error.
320 device::BluetoothSocket::ReceiveCompletionCallback receive_callback
;
321 EXPECT_CALL(*socket_
, Receive(_
, _
, _
))
322 .WillOnce(SaveArg
<1>(&receive_callback
));
323 receive_error_callback()->Run(device::BluetoothSocket::kSystemError
,
324 "The system is down. They're taking over!");
325 base::RunLoop run_loop
;
326 run_loop
.RunUntilIdle();
327 ASSERT_FALSE(receive_callback
.is_null());
329 // Receive some data.
330 scoped_refptr
<net::IOBuffer
> buffer
= CreateReceiveBuffer();
333 OnBytesReceived(std::string(kReceiveBufferContents
, kReceiveBufferSize
)));
334 EXPECT_CALL(*socket_
, Receive(_
, _
, _
));
335 receive_callback
.Run(kReceiveBufferSize
, buffer
);
336 base::RunLoop run_loop2
;
337 run_loop2
.RunUntilIdle();
339 // The connection disconnects and unregisters as an observer upon destruction.
340 EXPECT_CALL(*socket_
, Disconnect(_
));
341 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
344 TEST_F(ProximityAuthBluetoothConnectionTest
,
345 Disconnect_ConnectionWasAlreadyDisconnected
) {
346 StrictMock
<MockBluetoothConnection
> connection
;
347 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
348 connection
.Disconnect();
351 TEST_F(ProximityAuthBluetoothConnectionTest
,
352 Disconnect_ConnectionWasInProgress
) {
353 // Create an in-progress connection.
354 StrictMock
<MockBluetoothConnection
> connection
;
355 BeginConnecting(&connection
);
357 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
358 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
359 connection
.Disconnect();
362 TEST_F(ProximityAuthBluetoothConnectionTest
,
363 Disconnect_ConnectionWasConnected
) {
364 // Create a connected connection.
365 StrictMock
<MockBluetoothConnection
> connection
;
366 Connect(&connection
);
368 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
369 EXPECT_CALL(*socket_
, Disconnect(_
));
370 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
371 connection
.Disconnect();
374 TEST_F(ProximityAuthBluetoothConnectionTest
,
375 Connect_ThenDisconnectWhileInProgress_ThenBackingConnectionSucceeds
) {
376 StrictMock
<MockBluetoothConnection
> connection
;
377 device::BluetoothDevice::ConnectToServiceCallback callback
;
378 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
379 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
380 EXPECT_CALL(*adapter_
, AddObserver(&connection
));
381 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
))
382 .WillOnce(SaveArg
<1>(&callback
));
383 connection
.Connect();
384 ASSERT_FALSE(callback
.is_null());
386 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
387 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
388 connection
.Disconnect();
390 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
391 EXPECT_CALL(*socket_
, Receive(_
, _
, _
)).Times(0);
392 callback
.Run(socket_
);
395 TEST_F(ProximityAuthBluetoothConnectionTest
,
396 SendMessage_SendsExpectedDataOverTheWire
) {
397 // Create a connected connection.
398 StrictMock
<MockBluetoothConnection
> connection
;
399 Connect(&connection
);
401 scoped_refptr
<net::IOBuffer
> buffer
;
402 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
403 EXPECT_CALL(*socket_
, Send(_
, kSerializedMessageLength
, _
, _
))
404 .WillOnce(SaveArg
<0>(&buffer
));
405 connection
.SendMessage(wire_message
.Pass());
406 ASSERT_TRUE(buffer
.get());
407 EXPECT_EQ(kSerializedMessage
,
408 std::string(buffer
->data(), kSerializedMessageLength
));
410 // The connection disconnects and unregisters as an observer upon destruction.
411 EXPECT_CALL(*socket_
, Disconnect(_
));
412 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
415 TEST_F(ProximityAuthBluetoothConnectionTest
, SendMessage_Success
) {
416 // Create a connected connection.
417 StrictMock
<MockBluetoothConnection
> connection
;
418 Connect(&connection
);
420 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
421 // Ownership will be transfered below, so grab a reference here.
422 TestWireMessage
* expected_wire_message
= wire_message
.get();
424 device::BluetoothSocket::SendCompletionCallback callback
;
425 EXPECT_CALL(*socket_
, Send(_
, _
, _
, _
)).WillOnce(SaveArg
<2>(&callback
));
426 connection
.SendMessage(wire_message
.Pass());
427 ASSERT_FALSE(callback
.is_null());
429 EXPECT_CALL(connection
, OnDidSendMessage(Ref(*expected_wire_message
), true));
430 callback
.Run(kSerializedMessageLength
);
432 // The connection disconnects and unregisters as an observer upon destruction.
433 EXPECT_CALL(*socket_
, Disconnect(_
));
434 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
437 TEST_F(ProximityAuthBluetoothConnectionTest
, SendMessage_Failure
) {
438 // Create a connected connection.
439 StrictMock
<MockBluetoothConnection
> connection
;
440 Connect(&connection
);
442 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
443 // Ownership will be transfered below, so grab a reference here.
444 TestWireMessage
* expected_wire_message
= wire_message
.get();
446 device::BluetoothSocket::ErrorCompletionCallback error_callback
;
447 EXPECT_CALL(*socket_
, Send(_
, _
, _
, _
)).WillOnce(SaveArg
<3>(&error_callback
));
448 connection
.SendMessage(wire_message
.Pass());
450 ASSERT_FALSE(error_callback
.is_null());
451 EXPECT_CALL(connection
, OnDidSendMessage(Ref(*expected_wire_message
), false));
452 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
453 EXPECT_CALL(*socket_
, Disconnect(_
));
454 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
455 error_callback
.Run("The most helpful of error messages");
458 } // namespace proximity_auth