• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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