1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/acl_manager/acl_scheduler.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21
22 #include <chrono>
23 #include <future>
24
25 #include "hci/address.h"
26 #include "os/thread.h"
27
28 namespace bluetooth {
29 namespace hci {
30 namespace acl_manager {
31 namespace {
32
33 const auto address1 = Address::FromString("A1:A2:A3:A4:A5:A6").value();
34 const auto address2 = Address::FromString("B1:B2:B3:B4:B5:B6").value();
35 const auto address3 = Address::FromString("C1:C2:C3:C4:C5:C6").value();
36
37 const auto timeout = std::chrono::milliseconds(100);
38
39 MATCHER(IsSet, "Future is set") {
40 if (arg.wait_for(timeout) != std::future_status::ready) {
41 return false;
42 }
43 const_cast<std::future<void>&>(arg).get();
44 return true;
45 }
46
47 class AclSchedulerTest : public ::testing::Test {
48 protected:
SetUp()49 void SetUp() override {
50 fake_registry_.Start<AclScheduler>(&thread_);
51 ASSERT_TRUE(fake_registry_.IsStarted<AclScheduler>());
52
53 client_handler_ = fake_registry_.GetTestModuleHandler(&AclScheduler::Factory);
54 ASSERT_NE(client_handler_, nullptr);
55
56 acl_scheduler_ = static_cast<AclScheduler*>(fake_registry_.GetModuleUnderTest(&AclScheduler::Factory));
57
58 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
59 }
60
TearDown()61 void TearDown() override {
62 fake_registry_.SynchronizeModuleHandler(&AclScheduler::Factory, timeout);
63 fake_registry_.StopAll();
64 }
65
impossibleCallbackTakingString()66 common::ContextualOnceCallback<void(std::string)> impossibleCallbackTakingString() {
67 return client_handler_->BindOnce([](std::string /* _ */) { ADD_FAILURE(); });
68 }
69
emptyCallbackTakingString()70 common::ContextualOnceCallback<void(std::string)> emptyCallbackTakingString() {
71 return client_handler_->BindOnce([](std::string /* _ */) {});
72 }
73
promiseCallbackTakingString(std::promise<void> promise)74 common::ContextualOnceCallback<void(std::string)> promiseCallbackTakingString(std::promise<void> promise) {
75 return client_handler_->BindOnce(
76 [](std::promise<void> promise, std::string /* _ */) { promise.set_value(); },
77 std::move(promise));
78 }
79
impossibleCallback()80 common::ContextualOnceCallback<void()> impossibleCallback() {
81 return client_handler_->BindOnce([] { ADD_FAILURE(); });
82 }
83
emptyCallback()84 common::ContextualOnceCallback<void()> emptyCallback() {
85 return client_handler_->BindOnce([] {});
86 }
87
promiseCallback(std::promise<void> promise)88 common::ContextualOnceCallback<void()> promiseCallback(std::promise<void> promise) {
89 return client_handler_->BindOnce([](std::promise<void> promise) { promise.set_value(); }, std::move(promise));
90 }
91
92 TestModuleRegistry fake_registry_;
93 os::Thread& thread_ = fake_registry_.GetTestThread();
94 AclScheduler* acl_scheduler_ = nullptr;
95 os::Handler* client_handler_ = nullptr;
96 };
97
TEST_F(AclSchedulerTest,SingleConnectionImmediatelyExecuted)98 TEST_F(AclSchedulerTest, SingleConnectionImmediatelyExecuted) {
99 auto promise = std::promise<void>{};
100 auto future = promise.get_future();
101
102 // start connection, which should immediately execute
103 acl_scheduler_->EnqueueOutgoingAclConnection(address1, promiseCallback(std::move(promise)));
104
105 // it has started
106 EXPECT_THAT(future, IsSet());
107 }
108
TEST_F(AclSchedulerTest,ThreeConnectionsQueue)109 TEST_F(AclSchedulerTest, ThreeConnectionsQueue) {
110 auto promise1 = std::promise<void>{};
111 auto future1 = promise1.get_future();
112 auto promise2 = std::promise<void>{};
113 auto future2 = promise2.get_future();
114
115 // start first connection, which immediately runs
116 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
117 // start second connection
118 acl_scheduler_->EnqueueOutgoingAclConnection(address2, (promiseCallback(std::move(promise1))));
119 // start third connection
120 acl_scheduler_->EnqueueOutgoingAclConnection(address3, (promiseCallback(std::move(promise2))));
121
122 // the second and third connections are currently queued
123 EXPECT_THAT(future1.wait_for(timeout), std::future_status::timeout);
124
125 // first connection fails, so next one should start
126 acl_scheduler_->ReportOutgoingAclConnectionFailure();
127
128 // the second connection has started, the third one is queued
129 EXPECT_THAT(future1, IsSet());
130 EXPECT_THAT(future2.wait_for(timeout), std::future_status::timeout);
131
132 // second connection fails, so third one should start
133 acl_scheduler_->ReportOutgoingAclConnectionFailure();
134
135 // the third connection has started
136 EXPECT_THAT(future2, IsSet());
137 }
138
TEST_F(AclSchedulerTest,SingleConnectionCompletionCallback)139 TEST_F(AclSchedulerTest, SingleConnectionCompletionCallback) {
140 auto promise = std::promise<void>{};
141 auto future = promise.get_future();
142
143 // start connection, which immediately runs
144 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
145
146 // the outgoing connection completes
147 acl_scheduler_->ReportAclConnectionCompletion(
148 address1, promiseCallback(std::move(promise)), impossibleCallback(), impossibleCallbackTakingString());
149
150 // the outgoing_connection callback should have executed
151 EXPECT_THAT(future, IsSet());
152 }
153
TEST_F(AclSchedulerTest,SingleConnectionCompletionDequeueNext)154 TEST_F(AclSchedulerTest, SingleConnectionCompletionDequeueNext) {
155 auto promise = std::promise<void>{};
156 auto future = promise.get_future();
157
158 // start connection, which immediately runs
159 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
160 // start second connection which should queue
161 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
162
163 // complete the first connection
164 acl_scheduler_->ReportAclConnectionCompletion(
165 address1, emptyCallback(), impossibleCallback(), impossibleCallbackTakingString());
166
167 // the next connection should dequeue now
168 EXPECT_THAT(future, IsSet());
169 }
170
TEST_F(AclSchedulerTest,IncomingConnectionCallback)171 TEST_F(AclSchedulerTest, IncomingConnectionCallback) {
172 auto promise = std::promise<void>{};
173 auto future = promise.get_future();
174
175 // an incoming connection arrives
176 acl_scheduler_->RegisterPendingIncomingConnection(address1);
177
178 // and completes
179 acl_scheduler_->ReportAclConnectionCompletion(
180 address1, impossibleCallback(), promiseCallback(std::move(promise)), impossibleCallbackTakingString());
181
182 // the incoming_connection callback should have executed
183 EXPECT_THAT(future, IsSet());
184 }
185
TEST_F(AclSchedulerTest,UnknownConnectionCallback)186 TEST_F(AclSchedulerTest, UnknownConnectionCallback) {
187 auto promise = std::promise<void>{};
188 auto future = promise.get_future();
189
190 // start outgoing connection
191 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
192
193 // an incoming connection arrives
194 acl_scheduler_->RegisterPendingIncomingConnection(address2);
195
196 // then an unknown connection completes
197 acl_scheduler_->ReportAclConnectionCompletion(
198 address3, impossibleCallback(), impossibleCallback(), (promiseCallbackTakingString(std::move(promise))));
199
200 // the unknown_connection callback should have executed
201 EXPECT_THAT(future, IsSet());
202 }
203
TEST_F(AclSchedulerTest,TiebreakForOutgoingConnection)204 TEST_F(AclSchedulerTest, TiebreakForOutgoingConnection) {
205 auto promise = std::promise<void>{};
206 auto future = promise.get_future();
207
208 // start outgoing connection
209 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
210
211 // an incoming connection arrives *from the same address*
212 acl_scheduler_->RegisterPendingIncomingConnection(address1);
213
214 // then the connection to that address completes
215 acl_scheduler_->ReportAclConnectionCompletion(
216 address1, promiseCallback(std::move(promise)), impossibleCallback(), impossibleCallbackTakingString());
217
218 // the outgoing_connection callback should have executed, NOT the incoming_connection one
219 // this preserves working behavior, it is not based on any principled decision (so if you need to break this test,
220 // go for it)
221 EXPECT_THAT(future, IsSet());
222 }
223
TEST_F(AclSchedulerTest,QueueWhileIncomingConnectionsPending)224 TEST_F(AclSchedulerTest, QueueWhileIncomingConnectionsPending) {
225 auto promise = std::promise<void>{};
226 auto future = promise.get_future();
227
228 // start outgoing connection
229 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
230 // queue a second outgoing connection
231 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
232
233 // an incoming connection arrives
234 acl_scheduler_->RegisterPendingIncomingConnection(address3);
235
236 // then the first outgoing connection completes
237 acl_scheduler_->ReportAclConnectionCompletion(
238 address1, emptyCallback(), impossibleCallback(), impossibleCallbackTakingString());
239
240 // the outgoing_connection callback should not have executed yet
241 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
242
243 // now the incoming connection completes
244 acl_scheduler_->ReportAclConnectionCompletion(
245 address3, impossibleCallback(), emptyCallback(), impossibleCallbackTakingString());
246
247 // only now does the next outgoing connection start
248 EXPECT_THAT(future, IsSet());
249 }
250
TEST_F(AclSchedulerTest,DoNothingWhileIncomingConnectionsExist)251 TEST_F(AclSchedulerTest, DoNothingWhileIncomingConnectionsExist) {
252 auto promise = std::promise<void>{};
253 auto future = promise.get_future();
254
255 // an incoming connection arrives
256 acl_scheduler_->RegisterPendingIncomingConnection(address1);
257
258 // try to start an outgoing connection
259 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
260
261 // the outgoing_connection callback should not have executed yet
262 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
263
264 // a second incoming connection arrives
265 acl_scheduler_->RegisterPendingIncomingConnection(address3);
266
267 // the first incoming connection completes
268 acl_scheduler_->ReportAclConnectionCompletion(
269 address1, impossibleCallback(), emptyCallback(), impossibleCallbackTakingString());
270
271 // the outgoing_connection callback should *still* not have executed yet
272 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
273
274 // the second incoming connection completes, so none are left
275 acl_scheduler_->ReportAclConnectionCompletion(
276 address3, impossibleCallback(), emptyCallback(), impossibleCallbackTakingString());
277
278 // only now does the outgoing connection start
279 EXPECT_THAT(future, IsSet());
280 }
281
TEST_F(AclSchedulerTest,CancelOutgoingConnection)282 TEST_F(AclSchedulerTest, CancelOutgoingConnection) {
283 auto promise = std::promise<void>{};
284 auto future = promise.get_future();
285
286 // start an outgoing connection
287 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
288 // enqueue a second connection
289 acl_scheduler_->EnqueueOutgoingAclConnection(address2, promiseCallback(std::move(promise)));
290
291 // cancel the outgoing connection
292 acl_scheduler_->CancelAclConnection(address1, emptyCallback(), impossibleCallback());
293
294 // we expect the second connection to stay queued until the cancel completes
295 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
296
297 // now the cancel completes (with a failed status, in reality, but the scheduler doesn't care)
298 acl_scheduler_->ReportAclConnectionCompletion(
299 address1, emptyCallback(), impossibleCallback(), impossibleCallbackTakingString());
300
301 // so only now do we advance the queue
302 EXPECT_THAT(future, IsSet());
303 }
304
TEST_F(AclSchedulerTest,CancelOutgoingConnectionCallback)305 TEST_F(AclSchedulerTest, CancelOutgoingConnectionCallback) {
306 auto promise = std::promise<void>{};
307 auto future = promise.get_future();
308
309 // start an outgoing connection
310 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
311
312 // cancel the outgoing connection
313 acl_scheduler_->CancelAclConnection(address1, promiseCallback(std::move(promise)), impossibleCallback());
314
315 // we expect the cancel_connection callback to be invoked since we are cancelling an actually active connection
316 EXPECT_THAT(future, IsSet());
317 }
318
TEST_F(AclSchedulerTest,CancelQueuedConnectionRemoveFromQueue)319 TEST_F(AclSchedulerTest, CancelQueuedConnectionRemoveFromQueue) {
320 auto promise = std::promise<void>{};
321 auto future = promise.get_future();
322
323 // start an outgoing connection
324 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
325 // start another connection that will queue
326 acl_scheduler_->EnqueueOutgoingAclConnection(address2, impossibleCallback());
327 // start a third connection that will queue
328 acl_scheduler_->EnqueueOutgoingAclConnection(address3, promiseCallback(std::move(promise)));
329
330 // cancel the first queued connection
331 acl_scheduler_->CancelAclConnection(address2, impossibleCallback(), emptyCallback());
332
333 // the second queued connection should remain enqueued, since another connection is in progress
334 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
335
336 // complete the outgoing connection
337 acl_scheduler_->ReportOutgoingAclConnectionFailure();
338
339 // only now can we dequeue the second queued connection
340 EXPECT_THAT(future, IsSet());
341 }
342
TEST_F(AclSchedulerTest,CancelQueuedConnectionCallback)343 TEST_F(AclSchedulerTest, CancelQueuedConnectionCallback) {
344 auto promise = std::promise<void>{};
345 auto future = promise.get_future();
346
347 // start an outgoing connection
348 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
349 // start another connection that will queue
350 acl_scheduler_->EnqueueOutgoingAclConnection(address2, emptyCallback());
351
352 // cancel the queued connection
353 acl_scheduler_->CancelAclConnection(address2, impossibleCallback(), promiseCallback(std::move(promise)));
354
355 // we expect the cancel_connection_completed callback to be invoked since we are cancelling a connection in the queue
356 EXPECT_THAT(future, IsSet());
357 }
358
TEST_F(AclSchedulerTest,RemoteNameRequestImmediatelyExecuted)359 TEST_F(AclSchedulerTest, RemoteNameRequestImmediatelyExecuted) {
360 auto promise = std::promise<void>{};
361 auto future = promise.get_future();
362
363 // start an outgoing request
364 acl_scheduler_->EnqueueRemoteNameRequest(address1, promiseCallback(std::move(promise)), emptyCallback());
365
366 // we expect the start callback to be invoked immediately
367 EXPECT_THAT(future, IsSet());
368 }
369
TEST_F(AclSchedulerTest,RemoteNameRequestQueuing)370 TEST_F(AclSchedulerTest, RemoteNameRequestQueuing) {
371 auto promise = std::promise<void>{};
372 auto future = promise.get_future();
373
374 // start an outgoing request
375 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
376 // enqueue a second one
377 acl_scheduler_->EnqueueRemoteNameRequest(address2, promiseCallback(std::move(promise)), impossibleCallback());
378
379 // we should still be queued
380 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
381
382 // the first request completes
383 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
384
385 // so the second request should now have started
386 EXPECT_THAT(future, IsSet());
387 }
388
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationCallback)389 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationCallback) {
390 auto promise = std::promise<void>{};
391 auto future = promise.get_future();
392
393 // start an outgoing request
394 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
395
396 // cancel it
397 acl_scheduler_->CancelRemoteNameRequest(address1, promiseCallback(std::move(promise)));
398
399 // the cancel callback should be invoked
400 EXPECT_THAT(future, IsSet());
401 }
402
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationWhileQueuedCallback)403 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationWhileQueuedCallback) {
404 auto promise = std::promise<void>{};
405 auto future = promise.get_future();
406
407 // start an outgoing request
408 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
409 // enqueue a second one
410 acl_scheduler_->EnqueueRemoteNameRequest(address2, impossibleCallback(), promiseCallback(std::move(promise)));
411
412 // cancel the second one
413 acl_scheduler_->CancelRemoteNameRequest(address2, impossibleCallback());
414
415 // the cancel_request_completed calback should be invoked
416 EXPECT_THAT(future, IsSet());
417
418 // the first request completes
419 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
420
421 // we don't dequeue the second one, since it was cancelled
422 // implicitly assert that its callback was never invoked
423 }
424
TEST_F(AclSchedulerTest,CancelQueuedRemoteNameRequestRemoveFromQueue)425 TEST_F(AclSchedulerTest, CancelQueuedRemoteNameRequestRemoveFromQueue) {
426 auto promise = std::promise<void>{};
427 auto future = promise.get_future();
428
429 // start an outgoing connection
430 acl_scheduler_->EnqueueOutgoingAclConnection(address1, emptyCallback());
431 // start another connection that will queue
432 acl_scheduler_->EnqueueRemoteNameRequest(address2, impossibleCallback(), emptyCallback());
433 // start a third connection that will queue
434 acl_scheduler_->EnqueueRemoteNameRequest(address3, promiseCallback(std::move(promise)), impossibleCallback());
435
436 // cancel the first queued connection
437 acl_scheduler_->CancelRemoteNameRequest(address2, impossibleCallback());
438
439 // the second queued connection should remain enqueued, since another connection is in progress
440 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
441
442 // complete the outgoing connection
443 acl_scheduler_->ReportOutgoingAclConnectionFailure();
444
445 // only now can we dequeue the second queued connection
446 EXPECT_THAT(future, IsSet());
447 }
448
TEST_F(AclSchedulerTest,RemoteNameRequestCancellationShouldDequeueNext)449 TEST_F(AclSchedulerTest, RemoteNameRequestCancellationShouldDequeueNext) {
450 auto promise = std::promise<void>{};
451 auto future = promise.get_future();
452
453 // start an outgoing request
454 acl_scheduler_->EnqueueRemoteNameRequest(address1, emptyCallback(), impossibleCallback());
455 // enqueue a second one
456 acl_scheduler_->EnqueueRemoteNameRequest(address2, promiseCallback(std::move(promise)), impossibleCallback());
457
458 // we should still be queued
459 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
460
461 // the first request is cancelled
462 acl_scheduler_->CancelRemoteNameRequest(address1, emptyCallback());
463
464 // we should still remain queued while we wait for the cancel to complete
465 EXPECT_THAT(future.wait_for(timeout), std::future_status::timeout);
466
467 // the cancel completes
468 acl_scheduler_->ReportRemoteNameRequestCompletion(address1);
469
470 // so the second request should now have started
471 EXPECT_THAT(future, IsSet());
472 }
473
474 } // namespace
475 } // namespace acl_manager
476 } // namespace hci
477 } // namespace bluetooth
478