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_finder.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/time/time.h"
13 #include "components/proximity_auth/remote_device.h"
14 #include "components/proximity_auth/wire_message.h"
15 #include "device/bluetooth/bluetooth_adapter_factory.h"
16 #include "device/bluetooth/bluetooth_uuid.h"
17 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::NiceMock
;
23 using testing::Return
;
24 using testing::StrictMock
;
26 namespace proximity_auth
{
29 const char kDeviceName
[] = "Device name";
30 const char kPublicKey
[] = "Public key";
31 const char kBluetoothAddress
[] = "11:22:33:44:55:66";
32 const char kPersistentSymmetricKey
[] = "PSK";
34 const char kUuid
[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
36 RemoteDevice
CreateRemoteDevice() {
37 return RemoteDevice(kDeviceName
, kPublicKey
, kBluetoothAddress
,
38 kPersistentSymmetricKey
);
41 class MockConnection
: public Connection
{
43 MockConnection() : Connection(CreateRemoteDevice()) {}
44 ~MockConnection() override
{}
46 MOCK_METHOD0(Connect
, void());
48 using Connection::SetStatus
;
51 void Disconnect() override
{}
52 void SendMessageImpl(scoped_ptr
<WireMessage
> message
) override
{}
54 DISALLOW_COPY_AND_ASSIGN(MockConnection
);
57 class MockBluetoothConnectionFinder
: public BluetoothConnectionFinder
{
59 MockBluetoothConnectionFinder()
60 : BluetoothConnectionFinder(CreateRemoteDevice(),
61 device::BluetoothUUID(kUuid
),
63 ~MockBluetoothConnectionFinder() override
{}
65 MOCK_METHOD0(CreateConnectionProxy
, Connection
*());
67 // Creates a mock connection and sets an expectation that the mock connection
68 // finder's CreateConnection() method will be called and will return the
69 // created connection. Returns a reference to the created connection.
70 // NOTE: The returned connection's lifetime is managed by the connection
72 MockConnection
* ExpectCreateConnection() {
73 scoped_ptr
<MockConnection
> connection(new NiceMock
<MockConnection
>());
74 MockConnection
* connection_alias
= connection
.get();
75 EXPECT_CALL(*this, CreateConnectionProxy())
76 .WillOnce(Return(connection
.release()));
77 return connection_alias
;
80 using BluetoothConnectionFinder::AdapterPresentChanged
;
81 using BluetoothConnectionFinder::AdapterPoweredChanged
;
84 scoped_ptr
<Connection
> CreateConnection() override
{
85 return make_scoped_ptr(CreateConnectionProxy());
89 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnectionFinder
);
94 class ProximityAuthBluetoothConnectionFinderTest
: public testing::Test
{
96 ProximityAuthBluetoothConnectionFinderTest()
97 : adapter_(new NiceMock
<device::MockBluetoothAdapter
>),
98 connection_callback_(base::Bind(
99 &ProximityAuthBluetoothConnectionFinderTest::OnConnectionFound
,
100 base::Unretained(this))) {
101 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_
);
103 // By default, configure the environment to allow polling. Individual tests
104 // can override this as needed.
105 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(true));
106 ON_CALL(*adapter_
, IsPowered()).WillByDefault(Return(true));
109 MOCK_METHOD1(OnConnectionFoundProxy
, void(Connection
* connection
));
110 void OnConnectionFound(scoped_ptr
<Connection
> connection
) {
111 OnConnectionFoundProxy(connection
.get());
112 last_found_connection_
= connection
.Pass();
115 scoped_refptr
<device::MockBluetoothAdapter
> adapter_
;
116 ConnectionFinder::ConnectionCallback connection_callback_
;
119 // Save a pointer to the last found connection, to extend its lifetime.
120 scoped_ptr
<Connection
> last_found_connection_
;
122 base::MessageLoop message_loop_
;
125 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
126 ConstructAndDestroyDoesntCrash
) {
127 // Destroying a BluetoothConnectionFinder for which Find() has not been called
129 BluetoothConnectionFinder
connection_finder(
130 CreateRemoteDevice(), device::BluetoothUUID(kUuid
),
131 base::TimeDelta::FromMilliseconds(1));
134 TEST_F(ProximityAuthBluetoothConnectionFinderTest
, Find_NoBluetoothAdapter
) {
135 // Some platforms do not support Bluetooth. This test is only meaningful on
138 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
141 // The StrictMock will verify that no connection is created.
142 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
143 connection_finder
.Find(connection_callback_
);
146 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
147 Find_BluetoothAdapterNotPresent
) {
148 // The StrictMock will verify that no connection is created.
149 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
150 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(false));
151 connection_finder
.Find(connection_callback_
);
154 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
155 Find_BluetoothAdapterNotPowered
) {
156 // The StrictMock will verify that no connection is created.
157 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
158 ON_CALL(*adapter_
, IsPowered()).WillByDefault(Return(false));
159 connection_finder
.Find(connection_callback_
);
162 TEST_F(ProximityAuthBluetoothConnectionFinderTest
, Find_ConnectionSucceeds
) {
163 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
165 MockConnection
* connection
= connection_finder
.ExpectCreateConnection();
166 connection_finder
.Find(connection_callback_
);
168 connection
->SetStatus(Connection::IN_PROGRESS
);
170 EXPECT_CALL(*this, OnConnectionFoundProxy(_
));
171 connection
->SetStatus(Connection::CONNECTED
);
174 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
175 Find_ConnectionSucceeds_UnregistersAsObserver
) {
176 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
178 MockConnection
* connection
= connection_finder
.ExpectCreateConnection();
179 connection_finder
.Find(connection_callback_
);
181 connection
->SetStatus(Connection::IN_PROGRESS
);
183 EXPECT_CALL(*this, OnConnectionFoundProxy(_
));
184 EXPECT_CALL(*adapter_
, RemoveObserver(&connection_finder
));
185 connection
->SetStatus(Connection::CONNECTED
);
187 // If for some reason the connection sends more status updates, they should be
189 EXPECT_CALL(*this, OnConnectionFoundProxy(_
)).Times(0);
190 connection
->SetStatus(Connection::IN_PROGRESS
);
191 connection
->SetStatus(Connection::CONNECTED
);
194 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
195 Find_ConnectionFails_PostsTaskToPollAgain
) {
196 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
198 MockConnection
* connection
= connection_finder
.ExpectCreateConnection();
199 connection_finder
.Find(connection_callback_
);
201 // Simulate a connection that fails to connect.
202 connection
->SetStatus(Connection::IN_PROGRESS
);
203 connection
->SetStatus(Connection::DISCONNECTED
);
205 // A task should have been posted to poll again.
206 base::RunLoop run_loop
;
207 connection_finder
.ExpectCreateConnection();
208 run_loop
.RunUntilIdle();
211 TEST_F(ProximityAuthBluetoothConnectionFinderTest
, Find_PollsOnAdapterPresent
) {
212 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
214 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(false));
215 EXPECT_CALL(connection_finder
, CreateConnectionProxy()).Times(0);
216 connection_finder
.Find(connection_callback_
);
218 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(true));
219 connection_finder
.ExpectCreateConnection();
220 connection_finder
.AdapterPresentChanged(adapter_
.get(), true);
223 TEST_F(ProximityAuthBluetoothConnectionFinderTest
, Find_PollsOnAdapterPowered
) {
224 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
226 ON_CALL(*adapter_
, IsPowered()).WillByDefault(Return(false));
227 EXPECT_CALL(connection_finder
, CreateConnectionProxy()).Times(0);
228 connection_finder
.Find(connection_callback_
);
230 ON_CALL(*adapter_
, IsPowered()).WillByDefault(Return(true));
231 connection_finder
.ExpectCreateConnection();
232 connection_finder
.AdapterPoweredChanged(adapter_
.get(), true);
235 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
236 Find_DoesNotPollIfConnectionPending
) {
237 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
239 MockConnection
* connection
= connection_finder
.ExpectCreateConnection();
240 connection_finder
.Find(connection_callback_
);
242 connection
->SetStatus(Connection::IN_PROGRESS
);
244 // At this point, there is a pending connection in progress. Hence, an event
245 // that would normally trigger a new polling iteration should not do so now,
246 // because the delay interval between successive polling attempts has not yet
248 EXPECT_CALL(connection_finder
, CreateConnectionProxy()).Times(0);
249 connection_finder
.AdapterPresentChanged(adapter_
.get(), true);
252 TEST_F(ProximityAuthBluetoothConnectionFinderTest
,
253 Find_ConnectionFails_PostsTaskToPollAgain_PollWaitsForTask
) {
254 StrictMock
<MockBluetoothConnectionFinder
> connection_finder
;
256 MockConnection
* connection
= connection_finder
.ExpectCreateConnection();
257 connection_finder
.Find(connection_callback_
);
259 connection
->SetStatus(Connection::IN_PROGRESS
);
260 connection
->SetStatus(Connection::DISCONNECTED
);
262 // At this point, there is a pending poll scheduled. Hence, an event that
263 // would normally trigger a new polling iteration should not do so now,
264 // because the delay interval between successive polling attempts has not yet
266 EXPECT_CALL(connection_finder
, CreateConnectionProxy()).Times(0);
267 connection_finder
.AdapterPresentChanged(adapter_
.get(), true);
269 // Now, allow the pending task to run, but fail early, so that no new task is
271 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(false));
272 base::RunLoop run_loop
;
273 run_loop
.RunUntilIdle();
274 ON_CALL(*adapter_
, IsPresent()).WillByDefault(Return(true));
276 // Now that there is no pending task, events should once again trigger new
277 // polling iterations.
278 connection_finder
.ExpectCreateConnection();
279 connection_finder
.AdapterPresentChanged(adapter_
.get(), true);
282 } // namespace proximity_auth