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