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 kSerializedMessage
[] = "Yarrr, this be a serialized message. Yarr!";
39 const int kSerializedMessageLength
= strlen(kSerializedMessage
);
41 const char kUuid
[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
43 const RemoteDevice kRemoteDevice
= {kDeviceName
, kBluetoothAddress
};
45 const int kReceiveBufferSize
= 6;
46 const char kReceiveBufferContents
[] = "bytes";
48 // Create a buffer for testing received data.
49 scoped_refptr
<net::IOBuffer
> CreateReceiveBuffer() {
50 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(kReceiveBufferSize
);
51 memcpy(buffer
->data(), kReceiveBufferContents
, kReceiveBufferSize
);
55 class MockBluetoothConnection
: public BluetoothConnection
{
57 MockBluetoothConnection()
58 : BluetoothConnection(kRemoteDevice
, device::BluetoothUUID(kUuid
)) {}
60 // Calls back into the parent Connection class.
61 MOCK_METHOD1(SetStatusProxy
, void(Status status
));
62 MOCK_METHOD1(OnBytesReceived
, void(const std::string
& bytes
));
63 MOCK_METHOD2(OnDidSendMessage
,
64 void(const WireMessage
& message
, bool success
));
66 virtual void SetStatus(Status status
) override
{
67 SetStatusProxy(status
);
68 BluetoothConnection::SetStatus(status
);
71 using BluetoothConnection::status
;
72 using BluetoothConnection::Connect
;
73 using BluetoothConnection::DeviceRemoved
;
74 using BluetoothConnection::Disconnect
;
77 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection
);
80 class TestWireMessage
: public WireMessage
{
82 TestWireMessage() : WireMessage("permit id", "payload") {}
83 ~TestWireMessage() override
{}
85 std::string
Serialize() const override
{ return kSerializedMessage
; }
88 DISALLOW_COPY_AND_ASSIGN(TestWireMessage
);
93 class ProximityAuthBluetoothConnectionTest
: public testing::Test
{
95 ProximityAuthBluetoothConnectionTest()
96 : adapter_(new device::MockBluetoothAdapter
),
97 device_(adapter_
.get(), 0, kDeviceName
, kBluetoothAddress
, true, true),
98 socket_(new StrictMock
<device::MockBluetoothSocket
>),
100 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_
);
102 // Suppress uninteresting Gmock call warnings.
103 EXPECT_CALL(*adapter_
, GetDevice(_
)).Times(AnyNumber());
106 // Transition the connection into an in-progress state.
107 void BeginConnecting(MockBluetoothConnection
* connection
) {
108 EXPECT_EQ(Connection::DISCONNECTED
, connection
->status());
110 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
111 EXPECT_CALL(*connection
, SetStatusProxy(Connection::IN_PROGRESS
));
112 EXPECT_CALL(*adapter_
, AddObserver(connection
));
113 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
));
114 connection
->Connect();
116 EXPECT_EQ(Connection::IN_PROGRESS
, connection
->status());
119 // Transition the connection into a connected state.
120 // Saves the success and error callbacks passed into OnReceive(), which can be
121 // accessed via receive_callback() and receive_success_callback().
122 void Connect(MockBluetoothConnection
* connection
) {
123 EXPECT_EQ(Connection::DISCONNECTED
, connection
->status());
125 device::BluetoothDevice::ConnectToServiceCallback callback
;
126 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
127 EXPECT_CALL(*connection
, SetStatusProxy(Connection::IN_PROGRESS
));
128 EXPECT_CALL(*adapter_
, AddObserver(connection
));
129 EXPECT_CALL(device_
, ConnectToServiceInsecurely(_
, _
, _
))
130 .WillOnce(SaveArg
<1>(&callback
));
131 connection
->Connect();
132 ASSERT_FALSE(callback
.is_null());
134 EXPECT_CALL(*connection
, SetStatusProxy(Connection::CONNECTED
));
135 EXPECT_CALL(*socket_
, Receive(_
, _
, _
))
136 .WillOnce(DoAll(SaveArg
<1>(&receive_callback_
),
137 SaveArg
<2>(&receive_error_callback_
)));
138 callback
.Run(socket_
);
140 EXPECT_EQ(Connection::CONNECTED
, connection
->status());
143 device::BluetoothSocket::ReceiveCompletionCallback
* receive_callback() {
144 return &receive_callback_
;
146 device::BluetoothSocket::ReceiveErrorCompletionCallback
*
147 receive_error_callback() {
148 return &receive_error_callback_
;
152 // Mocks used for verifying interactions with the Bluetooth subsystem.
153 scoped_refptr
<device::MockBluetoothAdapter
> adapter_
;
154 NiceMock
<device::MockBluetoothDevice
> device_
;
155 scoped_refptr
<StrictMock
<device::MockBluetoothSocket
>> socket_
;
157 device::BluetoothUUID uuid_
;
160 base::MessageLoop message_loop_
;
162 device::BluetoothSocket::ReceiveCompletionCallback receive_callback_
;
163 device::BluetoothSocket::ReceiveErrorCompletionCallback
164 receive_error_callback_
;
167 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionWasInProgress
) {
168 // Create an in-progress connection.
169 StrictMock
<MockBluetoothConnection
> connection
;
170 BeginConnecting(&connection
);
172 // A second call to Connect() should be ignored.
173 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
174 connection
.Connect();
176 // The connection cleans up after itself upon destruction.
177 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
180 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionWasConnected
) {
181 // Create a connected connection.
182 StrictMock
<MockBluetoothConnection
> connection
;
183 Connect(&connection
);
185 // A second call to Connect() should be ignored.
186 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
187 connection
.Connect();
189 // The connection disconnects and unregisters as an observer upon destruction.
190 EXPECT_CALL(*socket_
, Disconnect(_
));
191 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
194 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_NoBluetoothAdapter
) {
195 // Some platforms do not support Bluetooth. This test is only meaningful on
198 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
201 StrictMock
<MockBluetoothConnection
> connection
;
202 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
203 connection
.Connect();
206 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_DeviceMissing
) {
207 StrictMock
<MockBluetoothConnection
> connection
;
209 ON_CALL(*adapter_
, GetDevice(_
))
210 .WillByDefault(Return(static_cast<device::BluetoothDevice
*>(NULL
)));
211 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
212 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
213 connection
.Connect();
216 TEST_F(ProximityAuthBluetoothConnectionTest
,
217 Connect_DeviceRemovedWhileConnecting
) {
218 // Create an in-progress connection.
219 StrictMock
<MockBluetoothConnection
> connection
;
220 BeginConnecting(&connection
);
222 // Remove the device while the connection is in-progress. This should cause
223 // the connection to disconnect.
224 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
225 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
226 connection
.DeviceRemoved(adapter_
.get(), &device_
);
229 TEST_F(ProximityAuthBluetoothConnectionTest
,
230 Connect_OtherDeviceRemovedWhileConnecting
) {
231 // Create an in-progress connection.
232 StrictMock
<MockBluetoothConnection
> connection
;
233 BeginConnecting(&connection
);
235 // Remove a device other than the one that is being connected to. This should
236 // not have any effect on the connection.
237 NiceMock
<device::MockBluetoothDevice
> other_device(
238 adapter_
.get(), 0, kOtherDeviceName
, kOtherBluetoothAddress
, true, true);
239 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
240 connection
.DeviceRemoved(adapter_
.get(), &other_device
);
242 // The connection removes itself as an observer when it is destroyed.
243 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
246 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionFails
) {
247 StrictMock
<MockBluetoothConnection
> connection
;
249 device::BluetoothDevice::ConnectToServiceErrorCallback error_callback
;
250 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
251 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
252 EXPECT_CALL(*adapter_
, AddObserver(&connection
));
253 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
))
254 .WillOnce(SaveArg
<2>(&error_callback
));
255 connection
.Connect();
256 ASSERT_FALSE(error_callback
.is_null());
258 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
259 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
260 error_callback
.Run("super descriptive error message");
263 TEST_F(ProximityAuthBluetoothConnectionTest
, Connect_ConnectionSucceeds
) {
264 StrictMock
<MockBluetoothConnection
> connection
;
265 Connect(&connection
);
267 // The connection disconnects and unregisters as an observer upon destruction.
268 EXPECT_CALL(*socket_
, Disconnect(_
));
269 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
272 TEST_F(ProximityAuthBluetoothConnectionTest
,
273 Connect_ConnectionSucceeds_ThenDeviceRemoved
) {
274 StrictMock
<MockBluetoothConnection
> connection
;
275 Connect(&connection
);
277 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
278 EXPECT_CALL(*socket_
, Disconnect(_
));
279 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
280 connection
.DeviceRemoved(adapter_
.get(), &device_
);
283 TEST_F(ProximityAuthBluetoothConnectionTest
,
284 Connect_ConnectionSucceeds_ReceiveData
) {
285 StrictMock
<MockBluetoothConnection
> connection
;
286 Connect(&connection
);
287 ASSERT_TRUE(receive_callback() && !receive_callback()->is_null());
289 // Receive some data. Once complete, the connection should re-register to be
290 // ready receive more data.
291 scoped_refptr
<net::IOBuffer
> buffer
= CreateReceiveBuffer();
294 OnBytesReceived(std::string(kReceiveBufferContents
, kReceiveBufferSize
)));
295 EXPECT_CALL(*socket_
, Receive(_
, _
, _
));
296 receive_callback()->Run(kReceiveBufferSize
, buffer
);
297 base::RunLoop run_loop
;
298 run_loop
.RunUntilIdle();
300 // The connection disconnects and unregisters as an observer upon destruction.
301 EXPECT_CALL(*socket_
, Disconnect(_
));
302 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
305 TEST_F(ProximityAuthBluetoothConnectionTest
,
306 Connect_ConnectionSucceeds_ReceiveDataAfterReceiveError
) {
307 StrictMock
<MockBluetoothConnection
> connection
;
308 Connect(&connection
);
309 ASSERT_TRUE(receive_error_callback() && !receive_error_callback()->is_null());
311 // Simulate an error while receiving data. The connection should re-register
312 // to be ready receive more data despite the error.
313 device::BluetoothSocket::ReceiveCompletionCallback receive_callback
;
314 EXPECT_CALL(*socket_
, Receive(_
, _
, _
))
315 .WillOnce(SaveArg
<1>(&receive_callback
));
316 receive_error_callback()->Run(device::BluetoothSocket::kSystemError
,
317 "The system is down. They're taking over!");
318 base::RunLoop run_loop
;
319 run_loop
.RunUntilIdle();
320 ASSERT_FALSE(receive_callback
.is_null());
322 // Receive some data.
323 scoped_refptr
<net::IOBuffer
> buffer
= CreateReceiveBuffer();
326 OnBytesReceived(std::string(kReceiveBufferContents
, kReceiveBufferSize
)));
327 EXPECT_CALL(*socket_
, Receive(_
, _
, _
));
328 receive_callback
.Run(kReceiveBufferSize
, buffer
);
329 base::RunLoop run_loop2
;
330 run_loop2
.RunUntilIdle();
332 // The connection disconnects and unregisters as an observer upon destruction.
333 EXPECT_CALL(*socket_
, Disconnect(_
));
334 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
337 TEST_F(ProximityAuthBluetoothConnectionTest
,
338 Disconnect_ConnectionWasAlreadyDisconnected
) {
339 StrictMock
<MockBluetoothConnection
> connection
;
340 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
341 connection
.Disconnect();
344 TEST_F(ProximityAuthBluetoothConnectionTest
,
345 Disconnect_ConnectionWasInProgress
) {
346 // Create an in-progress connection.
347 StrictMock
<MockBluetoothConnection
> connection
;
348 BeginConnecting(&connection
);
350 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
351 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
352 connection
.Disconnect();
355 TEST_F(ProximityAuthBluetoothConnectionTest
,
356 Disconnect_ConnectionWasConnected
) {
357 // Create a connected connection.
358 StrictMock
<MockBluetoothConnection
> connection
;
359 Connect(&connection
);
361 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
362 EXPECT_CALL(*socket_
, Disconnect(_
));
363 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
364 connection
.Disconnect();
367 TEST_F(ProximityAuthBluetoothConnectionTest
,
368 Connect_ThenDisconnectWhileInProgress_ThenBackingConnectionSucceeds
) {
369 StrictMock
<MockBluetoothConnection
> connection
;
370 device::BluetoothDevice::ConnectToServiceCallback callback
;
371 ON_CALL(*adapter_
, GetDevice(_
)).WillByDefault(Return(&device_
));
372 EXPECT_CALL(connection
, SetStatusProxy(Connection::IN_PROGRESS
));
373 EXPECT_CALL(*adapter_
, AddObserver(&connection
));
374 EXPECT_CALL(device_
, ConnectToServiceInsecurely(uuid_
, _
, _
))
375 .WillOnce(SaveArg
<1>(&callback
));
376 connection
.Connect();
377 ASSERT_FALSE(callback
.is_null());
379 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
380 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
381 connection
.Disconnect();
383 EXPECT_CALL(connection
, SetStatusProxy(_
)).Times(0);
384 EXPECT_CALL(*socket_
, Receive(_
, _
, _
)).Times(0);
385 callback
.Run(socket_
);
388 TEST_F(ProximityAuthBluetoothConnectionTest
,
389 SendMessage_SendsExpectedDataOverTheWire
) {
390 // Create a connected connection.
391 StrictMock
<MockBluetoothConnection
> connection
;
392 Connect(&connection
);
394 scoped_refptr
<net::IOBuffer
> buffer
;
395 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
396 EXPECT_CALL(*socket_
, Send(_
, kSerializedMessageLength
, _
, _
))
397 .WillOnce(SaveArg
<0>(&buffer
));
398 connection
.SendMessage(wire_message
.Pass());
399 ASSERT_TRUE(buffer
.get());
400 EXPECT_EQ(kSerializedMessage
,
401 std::string(buffer
->data(), kSerializedMessageLength
));
403 // The connection disconnects and unregisters as an observer upon destruction.
404 EXPECT_CALL(*socket_
, Disconnect(_
));
405 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
408 TEST_F(ProximityAuthBluetoothConnectionTest
, SendMessage_Success
) {
409 // Create a connected connection.
410 StrictMock
<MockBluetoothConnection
> connection
;
411 Connect(&connection
);
413 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
414 // Ownership will be transfered below, so grab a reference here.
415 TestWireMessage
* expected_wire_message
= wire_message
.get();
417 device::BluetoothSocket::SendCompletionCallback callback
;
418 EXPECT_CALL(*socket_
, Send(_
, _
, _
, _
)).WillOnce(SaveArg
<2>(&callback
));
419 connection
.SendMessage(wire_message
.Pass());
420 ASSERT_FALSE(callback
.is_null());
422 EXPECT_CALL(connection
, OnDidSendMessage(Ref(*expected_wire_message
), true));
423 callback
.Run(kSerializedMessageLength
);
425 // The connection disconnects and unregisters as an observer upon destruction.
426 EXPECT_CALL(*socket_
, Disconnect(_
));
427 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
430 TEST_F(ProximityAuthBluetoothConnectionTest
, SendMessage_Failure
) {
431 // Create a connected connection.
432 StrictMock
<MockBluetoothConnection
> connection
;
433 Connect(&connection
);
435 scoped_ptr
<TestWireMessage
> wire_message(new TestWireMessage
);
436 // Ownership will be transfered below, so grab a reference here.
437 TestWireMessage
* expected_wire_message
= wire_message
.get();
439 device::BluetoothSocket::ErrorCompletionCallback error_callback
;
440 EXPECT_CALL(*socket_
, Send(_
, _
, _
, _
)).WillOnce(SaveArg
<3>(&error_callback
));
441 connection
.SendMessage(wire_message
.Pass());
443 ASSERT_FALSE(error_callback
.is_null());
444 EXPECT_CALL(connection
, OnDidSendMessage(Ref(*expected_wire_message
), false));
445 EXPECT_CALL(connection
, SetStatusProxy(Connection::DISCONNECTED
));
446 EXPECT_CALL(*socket_
, Disconnect(_
));
447 EXPECT_CALL(*adapter_
, RemoveObserver(&connection
));
448 error_callback
.Run("The most helpful of error messages");
451 } // namespace proximity_auth