OLD | NEW |
| (Empty) |
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_finder.h" | |
6 | |
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 "testing/gmock/include/gmock/gmock.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 using testing::_; | |
22 using testing::NiceMock; | |
23 using testing::Return; | |
24 using testing::StrictMock; | |
25 | |
26 namespace proximity_auth { | |
27 namespace { | |
28 | |
29 const char kDeviceName[] = "Device name"; | |
30 const char kBluetoothAddress[] = "11:22:33:44:55:66"; | |
31 const RemoteDevice kRemoteDevice = {kDeviceName, kBluetoothAddress}; | |
32 | |
33 const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF"; | |
34 | |
35 class MockConnection : public Connection { | |
36 public: | |
37 MockConnection() : Connection(kRemoteDevice) {} | |
38 virtual ~MockConnection() {} | |
39 | |
40 MOCK_METHOD0(Connect, void()); | |
41 | |
42 using Connection::SetStatus; | |
43 | |
44 private: | |
45 void Disconnect() {} | |
46 void SendMessageImpl(scoped_ptr<WireMessage> message) {} | |
47 | |
48 DISALLOW_COPY_AND_ASSIGN(MockConnection); | |
49 }; | |
50 | |
51 class MockBluetoothConnectionFinder : public BluetoothConnectionFinder { | |
52 public: | |
53 MockBluetoothConnectionFinder() | |
54 : BluetoothConnectionFinder(kRemoteDevice, | |
55 device::BluetoothUUID(kUuid), | |
56 base::TimeDelta()) {} | |
57 virtual ~MockBluetoothConnectionFinder() {} | |
58 | |
59 MOCK_METHOD0(CreateConnectionProxy, Connection*()); | |
60 | |
61 // Creates a mock connection and sets an expectation that the mock connection | |
62 // finder's CreateConnection() method will be called and will return the | |
63 // created connection. Returns a reference to the created connection. | |
64 // NOTE: The returned connection's lifetime is managed by the connection | |
65 // finder. | |
66 MockConnection* ExpectCreateConnection() { | |
67 scoped_ptr<MockConnection> connection(new NiceMock<MockConnection>()); | |
68 MockConnection* connection_alias = connection.get(); | |
69 EXPECT_CALL(*this, CreateConnectionProxy()) | |
70 .WillOnce(Return(connection.release())); | |
71 return connection_alias; | |
72 } | |
73 | |
74 using BluetoothConnectionFinder::AdapterPresentChanged; | |
75 using BluetoothConnectionFinder::AdapterPoweredChanged; | |
76 | |
77 protected: | |
78 virtual scoped_ptr<Connection> CreateConnection() override { | |
79 return make_scoped_ptr(CreateConnectionProxy()); | |
80 } | |
81 | |
82 private: | |
83 DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnectionFinder); | |
84 }; | |
85 | |
86 } // namespace | |
87 | |
88 class ProximityAuthBluetoothConnectionFinderTest : public testing::Test { | |
89 protected: | |
90 ProximityAuthBluetoothConnectionFinderTest() | |
91 : adapter_(new NiceMock<device::MockBluetoothAdapter>), | |
92 connection_callback_(base::Bind( | |
93 &ProximityAuthBluetoothConnectionFinderTest::OnConnectionFound, | |
94 base::Unretained(this))) { | |
95 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); | |
96 | |
97 // By default, configure the environment to allow polling. Individual tests | |
98 // can override this as needed. | |
99 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true)); | |
100 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true)); | |
101 } | |
102 | |
103 MOCK_METHOD1(OnConnectionFoundProxy, void(Connection* connection)); | |
104 void OnConnectionFound(scoped_ptr<Connection> connection) { | |
105 OnConnectionFoundProxy(connection.get()); | |
106 last_found_connection_ = connection.Pass(); | |
107 } | |
108 | |
109 scoped_refptr<device::MockBluetoothAdapter> adapter_; | |
110 ConnectionFinder::ConnectionCallback connection_callback_; | |
111 | |
112 private: | |
113 // Save a pointer to the last found connection, to extend its lifetime. | |
114 scoped_ptr<Connection> last_found_connection_; | |
115 | |
116 base::MessageLoop message_loop_; | |
117 }; | |
118 | |
119 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
120 ConstructAndDestroyDoesntCrash) { | |
121 // Destroying a BluetoothConnectionFinder for which Find() has not been called | |
122 // should not crash. | |
123 BluetoothConnectionFinder connection_finder( | |
124 kRemoteDevice, | |
125 device::BluetoothUUID(kUuid), | |
126 base::TimeDelta::FromMilliseconds(1)); | |
127 } | |
128 | |
129 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_NoBluetoothAdapter) { | |
130 // Some platforms do not support Bluetooth. This test is only meaningful on | |
131 // those platforms. | |
132 adapter_ = NULL; | |
133 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) | |
134 return; | |
135 | |
136 // The StrictMock will verify that no connection is created. | |
137 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
138 connection_finder.Find(connection_callback_); | |
139 } | |
140 | |
141 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
142 Find_BluetoothAdapterNotPresent) { | |
143 // The StrictMock will verify that no connection is created. | |
144 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
145 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false)); | |
146 connection_finder.Find(connection_callback_); | |
147 } | |
148 | |
149 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
150 Find_BluetoothAdapterNotPowered) { | |
151 // The StrictMock will verify that no connection is created. | |
152 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
153 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false)); | |
154 connection_finder.Find(connection_callback_); | |
155 } | |
156 | |
157 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_ConnectionSucceeds) { | |
158 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
159 | |
160 MockConnection* connection = connection_finder.ExpectCreateConnection(); | |
161 connection_finder.Find(connection_callback_); | |
162 | |
163 connection->SetStatus(Connection::IN_PROGRESS); | |
164 | |
165 EXPECT_CALL(*this, OnConnectionFoundProxy(_)); | |
166 connection->SetStatus(Connection::CONNECTED); | |
167 } | |
168 | |
169 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
170 Find_ConnectionSucceeds_UnregistersAsObserver) { | |
171 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
172 | |
173 MockConnection* connection = connection_finder.ExpectCreateConnection(); | |
174 connection_finder.Find(connection_callback_); | |
175 | |
176 connection->SetStatus(Connection::IN_PROGRESS); | |
177 | |
178 EXPECT_CALL(*this, OnConnectionFoundProxy(_)); | |
179 EXPECT_CALL(*adapter_, RemoveObserver(&connection_finder)); | |
180 connection->SetStatus(Connection::CONNECTED); | |
181 | |
182 // If for some reason the connection sends more status updates, they should be | |
183 // ignored. | |
184 EXPECT_CALL(*this, OnConnectionFoundProxy(_)).Times(0); | |
185 connection->SetStatus(Connection::IN_PROGRESS); | |
186 connection->SetStatus(Connection::CONNECTED); | |
187 } | |
188 | |
189 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
190 Find_ConnectionFails_PostsTaskToPollAgain) { | |
191 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
192 | |
193 MockConnection* connection = connection_finder.ExpectCreateConnection(); | |
194 connection_finder.Find(connection_callback_); | |
195 | |
196 // Simulate a connection that fails to connect. | |
197 connection->SetStatus(Connection::IN_PROGRESS); | |
198 connection->SetStatus(Connection::DISCONNECTED); | |
199 | |
200 // A task should have been posted to poll again. | |
201 base::RunLoop run_loop; | |
202 connection_finder.ExpectCreateConnection(); | |
203 run_loop.RunUntilIdle(); | |
204 } | |
205 | |
206 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPresent) { | |
207 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
208 | |
209 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false)); | |
210 EXPECT_CALL(connection_finder, CreateConnectionProxy()).Times(0); | |
211 connection_finder.Find(connection_callback_); | |
212 | |
213 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true)); | |
214 connection_finder.ExpectCreateConnection(); | |
215 connection_finder.AdapterPresentChanged(adapter_.get(), true); | |
216 } | |
217 | |
218 TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPowered) { | |
219 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
220 | |
221 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false)); | |
222 EXPECT_CALL(connection_finder, CreateConnectionProxy()).Times(0); | |
223 connection_finder.Find(connection_callback_); | |
224 | |
225 ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true)); | |
226 connection_finder.ExpectCreateConnection(); | |
227 connection_finder.AdapterPoweredChanged(adapter_.get(), true); | |
228 } | |
229 | |
230 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
231 Find_DoesNotPollIfConnectionPending) { | |
232 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
233 | |
234 MockConnection* connection = connection_finder.ExpectCreateConnection(); | |
235 connection_finder.Find(connection_callback_); | |
236 | |
237 connection->SetStatus(Connection::IN_PROGRESS); | |
238 | |
239 // At this point, there is a pending connection in progress. Hence, an event | |
240 // that would normally trigger a new polling iteration should not do so now, | |
241 // because the delay interval between successive polling attempts has not yet | |
242 // expired. | |
243 EXPECT_CALL(connection_finder, CreateConnectionProxy()).Times(0); | |
244 connection_finder.AdapterPresentChanged(adapter_.get(), true); | |
245 } | |
246 | |
247 TEST_F(ProximityAuthBluetoothConnectionFinderTest, | |
248 Find_ConnectionFails_PostsTaskToPollAgain_PollWaitsForTask) { | |
249 StrictMock<MockBluetoothConnectionFinder> connection_finder; | |
250 | |
251 MockConnection* connection = connection_finder.ExpectCreateConnection(); | |
252 connection_finder.Find(connection_callback_); | |
253 | |
254 connection->SetStatus(Connection::IN_PROGRESS); | |
255 connection->SetStatus(Connection::DISCONNECTED); | |
256 | |
257 // At this point, there is a pending poll scheduled. Hence, an event that | |
258 // would normally trigger a new polling iteration should not do so now, | |
259 // because the delay interval between successive polling attempts has not yet | |
260 // expired. | |
261 EXPECT_CALL(connection_finder, CreateConnectionProxy()).Times(0); | |
262 connection_finder.AdapterPresentChanged(adapter_.get(), true); | |
263 | |
264 // Now, allow the pending task to run, but fail early, so that no new task is | |
265 // posted. | |
266 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false)); | |
267 base::RunLoop run_loop; | |
268 run_loop.RunUntilIdle(); | |
269 ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true)); | |
270 | |
271 // Now that there is no pending task, events should once again trigger new | |
272 // polling iterations. | |
273 connection_finder.ExpectCreateConnection(); | |
274 connection_finder.AdapterPresentChanged(adapter_.get(), true); | |
275 } | |
276 | |
277 } // namespace proximity_auth | |
OLD | NEW |