Update mojo sdk to rev c02a28868825edfa57ab77947b8cb15e741c5598
[chromium-blink-merge.git] / components / proximity_auth / bluetooth_connection_finder_unittest.cc
blob393f73478a2ad436d5ef8ec24af614658158e751
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"
7 #include "base/bind.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 "device/bluetooth/test/mock_bluetooth_device.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::_;
23 using testing::NiceMock;
24 using testing::Return;
25 using testing::StrictMock;
27 namespace proximity_auth {
28 namespace {
30 const char kDeviceName[] = "Device name";
31 const char kPublicKey[] = "Public key";
32 const char kBluetoothAddress[] = "11:22:33:44:55:66";
33 const char kPersistentSymmetricKey[] = "PSK";
35 const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
37 RemoteDevice CreateRemoteDevice() {
38 return RemoteDevice(kDeviceName, kPublicKey, kBluetoothAddress,
39 kPersistentSymmetricKey);
42 class MockConnection : public Connection {
43 public:
44 MockConnection() : Connection(CreateRemoteDevice()), do_not_destroy_(false) {}
45 ~MockConnection() override { EXPECT_FALSE(do_not_destroy_); }
47 MOCK_METHOD0(Connect, void());
49 void SetStatus(Connection::Status status) {
50 // This object should not be destroyed after setting the status and calling
51 // observers.
52 do_not_destroy_ = true;
53 Connection::SetStatus(status);
54 do_not_destroy_ = false;
57 private:
58 void Disconnect() override {}
59 void SendMessageImpl(scoped_ptr<WireMessage> message) override {}
61 // If true, we do not expect |this| object to be destroyed until this value is
62 // toggled back to false.
63 bool do_not_destroy_;
65 DISALLOW_COPY_AND_ASSIGN(MockConnection);
68 class MockBluetoothConnectionFinder : public BluetoothConnectionFinder {
69 public:
70 MockBluetoothConnectionFinder()
71 : BluetoothConnectionFinder(CreateRemoteDevice(),
72 device::BluetoothUUID(kUuid),
73 base::TimeDelta()) {}
74 ~MockBluetoothConnectionFinder() override {}
76 MOCK_METHOD0(CreateConnectionProxy, Connection*());
78 // Creates a mock connection and sets an expectation that the mock connection
79 // finder's CreateConnection() method will be called and will return the
80 // created connection. Returns a reference to the created connection.
81 // NOTE: The returned connection's lifetime is managed by the connection
82 // finder.
83 MockConnection* ExpectCreateConnection() {
84 scoped_ptr<MockConnection> connection(new NiceMock<MockConnection>());
85 MockConnection* connection_alias = connection.get();
86 EXPECT_CALL(*this, CreateConnectionProxy())
87 .WillOnce(Return(connection.release()));
88 return connection_alias;
91 using BluetoothConnectionFinder::AdapterPresentChanged;
92 using BluetoothConnectionFinder::AdapterPoweredChanged;
94 void ClearSeekCallbacks() {
95 seek_callback_ = base::Closure();
96 seek_error_callback_ = bluetooth_util::ErrorCallback();
99 const base::Closure& seek_callback() { return seek_callback_; }
100 const bluetooth_util::ErrorCallback& seek_error_callback() {
101 return seek_error_callback_;
104 protected:
105 // BluetoothConnectionFinder:
106 scoped_ptr<Connection> CreateConnection() override {
107 return make_scoped_ptr(CreateConnectionProxy());
110 void SeekDeviceByAddress(
111 const std::string& bluetooth_address,
112 const base::Closure& callback,
113 const bluetooth_util::ErrorCallback& error_callback) override {
114 EXPECT_EQ(kBluetoothAddress, bluetooth_address);
115 seek_callback_ = callback;
116 seek_error_callback_ = error_callback;
119 private:
120 base::Closure seek_callback_;
121 bluetooth_util::ErrorCallback seek_error_callback_;
123 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnectionFinder);
126 } // namespace
128 class ProximityAuthBluetoothConnectionFinderTest : public testing::Test {
129 protected:
130 ProximityAuthBluetoothConnectionFinderTest()
131 : adapter_(new NiceMock<device::MockBluetoothAdapter>),
132 bluetooth_device_(new NiceMock<device::MockBluetoothDevice>(
133 adapter_.get(),
134 device::BluetoothDevice::DEVICE_PHONE,
135 kDeviceName,
136 kBluetoothAddress,
137 true,
138 false)),
139 connection_callback_(base::Bind(
140 &ProximityAuthBluetoothConnectionFinderTest::OnConnectionFound,
141 base::Unretained(this))) {
142 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
144 // By default, configure the environment to allow polling. Individual tests
145 // can override this as needed.
146 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
147 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
149 // By default, the remote device is known to |adapter_| so
150 // |SeekDeviceByAddress()| will not be called.
151 ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
152 .WillByDefault(Return(bluetooth_device_.get()));
155 MOCK_METHOD1(OnConnectionFoundProxy, void(Connection* connection));
156 void OnConnectionFound(scoped_ptr<Connection> connection) {
157 OnConnectionFoundProxy(connection.get());
158 last_found_connection_ = connection.Pass();
161 // Starts |connection_finder_|. If |expect_connection| is true, then we set an
162 // expectation that an in-progress connection will be created and returned.
163 MockConnection* StartConnectionFinder(bool expect_connection) {
164 MockConnection* connection = nullptr;
165 if (expect_connection)
166 connection = connection_finder_.ExpectCreateConnection();
167 connection_finder_.Find(connection_callback_);
168 return connection;
171 // Given an in-progress |connection| returned by |StartConnectionFinder()|,
172 // simulate it transitioning to the CONNECTED state.
173 void SimulateDeviceConnection(MockConnection* connection) {
174 connection->SetStatus(Connection::IN_PROGRESS);
175 base::RunLoop run_loop;
176 EXPECT_CALL(*this, OnConnectionFoundProxy(_));
177 connection->SetStatus(Connection::CONNECTED);
178 run_loop.RunUntilIdle();
181 scoped_refptr<device::MockBluetoothAdapter> adapter_;
182 StrictMock<MockBluetoothConnectionFinder> connection_finder_;
183 scoped_ptr<device::MockBluetoothDevice> bluetooth_device_;
184 ConnectionFinder::ConnectionCallback connection_callback_;
186 private:
187 // Save a pointer to the last found connection, to extend its lifetime.
188 scoped_ptr<Connection> last_found_connection_;
190 base::MessageLoop message_loop_;
193 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
194 ConstructAndDestroyDoesntCrash) {
195 // Destroying a BluetoothConnectionFinder for which Find() has not been called
196 // should not crash.
197 BluetoothConnectionFinder connection_finder(
198 CreateRemoteDevice(), device::BluetoothUUID(kUuid),
199 base::TimeDelta::FromMilliseconds(1));
202 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_NoBluetoothAdapter) {
203 // Some platforms do not support Bluetooth. This test is only meaningful on
204 // those platforms.
205 adapter_ = NULL;
206 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
207 return;
209 // The StrictMock will verify that no connection is created.
210 StartConnectionFinder(false);
213 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
214 Find_BluetoothAdapterNotPresent) {
215 // The StrictMock will verify that no connection is created.
216 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
217 StartConnectionFinder(false);
220 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
221 Find_BluetoothAdapterNotPowered) {
222 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false));
223 // The StrictMock will verify that no connection is created.
224 StartConnectionFinder(false);
227 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_ConnectionSucceeds) {
228 MockConnection* connection = StartConnectionFinder(true);
229 SimulateDeviceConnection(connection);
232 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
233 Find_ConnectionSucceeds_UnregistersAsObserver) {
234 MockConnection* connection = StartConnectionFinder(true);
235 SimulateDeviceConnection(connection);
237 // If for some reason the connection sends more status updates, they should
238 // be ignored.
239 base::RunLoop run_loop;
240 EXPECT_CALL(*this, OnConnectionFoundProxy(_)).Times(0);
241 connection->SetStatus(Connection::IN_PROGRESS);
242 connection->SetStatus(Connection::CONNECTED);
243 run_loop.RunUntilIdle();
246 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
247 Find_ConnectionFails_PostsTaskToPollAgain) {
248 MockConnection* connection = StartConnectionFinder(true);
250 // Simulate a connection that fails to connect.
251 connection->SetStatus(Connection::IN_PROGRESS);
252 connection->SetStatus(Connection::DISCONNECTED);
254 // A task should have been posted to poll again.
255 base::RunLoop run_loop;
256 connection_finder_.ExpectCreateConnection();
257 run_loop.RunUntilIdle();
260 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPresent) {
261 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
262 EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
263 connection_finder_.Find(connection_callback_);
265 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
266 connection_finder_.ExpectCreateConnection();
267 connection_finder_.AdapterPresentChanged(adapter_.get(), true);
270 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPowered) {
271 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false));
272 EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
273 connection_finder_.Find(connection_callback_);
275 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
276 connection_finder_.ExpectCreateConnection();
277 connection_finder_.AdapterPoweredChanged(adapter_.get(), true);
280 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
281 Find_DoesNotPollIfConnectionPending) {
282 MockConnection* connection = StartConnectionFinder(true);
284 connection->SetStatus(Connection::IN_PROGRESS);
286 // At this point, there is a pending connection in progress. Hence, an event
287 // that would normally trigger a new polling iteration should not do so now,
288 // because the delay interval between successive polling attempts has not yet
289 // expired.
290 EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
291 connection_finder_.AdapterPresentChanged(adapter_.get(), true);
294 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
295 Find_ConnectionFails_PostsTaskToPollAgain_PollWaitsForTask) {
296 MockConnection* connection = StartConnectionFinder(true);
298 connection->SetStatus(Connection::IN_PROGRESS);
299 connection->SetStatus(Connection::DISCONNECTED);
301 // At this point, there is a pending poll scheduled. Hence, an event that
302 // would normally trigger a new polling iteration should not do so now,
303 // because the delay interval between successive polling attempts has not yet
304 // expired.
305 EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
306 connection_finder_.AdapterPresentChanged(adapter_.get(), true);
308 // Now, allow the pending task to run, but fail early, so that no new task is
309 // posted.
310 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
311 base::RunLoop run_loop;
312 run_loop.RunUntilIdle();
313 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
315 // Now that there is no pending task, events should once again trigger new
316 // polling iterations.
317 connection_finder_.ExpectCreateConnection();
318 connection_finder_.AdapterPresentChanged(adapter_.get(), true);
321 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
322 Find_DeviceNotKnown_SeekDeviceSucceeds) {
323 // If the BluetoothDevice is not known by the adapter, |connection_finder|
324 // will call SeekDeviceByAddress() first to make it known.
325 ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
326 .WillByDefault(Return(nullptr));
327 connection_finder_.Find(connection_callback_);
328 ASSERT_FALSE(connection_finder_.seek_callback().is_null());
329 EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
331 // After seeking is successful, the normal flow should resume.
332 ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
333 .WillByDefault(Return(bluetooth_device_.get()));
334 MockConnection* connection = connection_finder_.ExpectCreateConnection();
335 connection_finder_.seek_callback().Run();
336 SimulateDeviceConnection(connection);
339 TEST_F(ProximityAuthBluetoothConnectionFinderTest,
340 Find_DeviceNotKnown_SeekDeviceFailThenSucceeds) {
341 // If the BluetoothDevice is not known by the adapter, |connection_finder|
342 // will call SeekDeviceByAddress() first to make it known.
343 ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
344 .WillByDefault(Return(nullptr));
345 connection_finder_.Find(connection_callback_);
346 EXPECT_FALSE(connection_finder_.seek_callback().is_null());
347 ASSERT_FALSE(connection_finder_.seek_error_callback().is_null());
349 // If the seek fails, then |connection_finder| will post a delayed poll to
350 // reattempt the seek.
351 connection_finder_.seek_error_callback().Run("Seek failed for test.");
352 connection_finder_.ClearSeekCallbacks();
353 EXPECT_TRUE(connection_finder_.seek_callback().is_null());
354 EXPECT_TRUE(connection_finder_.seek_error_callback().is_null());
356 // Check that seek is reattempted.
357 base::RunLoop run_loop;
358 run_loop.RunUntilIdle();
359 ASSERT_FALSE(connection_finder_.seek_callback().is_null());
360 EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
362 // Successfully connect to the Bluetooth device.
363 ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
364 .WillByDefault(Return(bluetooth_device_.get()));
365 MockConnection* connection = connection_finder_.ExpectCreateConnection();
366 connection_finder_.seek_callback().Run();
367 SimulateDeviceConnection(connection);
370 } // namespace proximity_auth