[bt][gap-le] Make Disconnect on unconnected peers return true
Change the contract of LowEnergyConnectionManager::Disconnect from
"perform disconnection on peer" to "ensure that peer is disconnected."
BT-824
BT-652
Test: In bt-host-unittests
GAP_LowEnergyConnectionManagerTest.Disconnect*
Change-Id: I3cbee118dd306c10df76815c1e9ab0b92a6870f8
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.cc b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.cc
index 6c99295..99bd726 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.cc
@@ -536,15 +536,14 @@
auto iter = connections_.find(peer_id);
if (iter == connections_.end()) {
bt_log(WARN, "gap-le", "peer not connected (id: %s)", bt_str(peer_id));
- return false;
+ return true;
}
// Remove the connection state from the internal map right away.
auto conn = std::move(iter->second);
connections_.erase(iter);
- bt_log(INFO, "gap-le", "disconnecting link: %s",
- conn->link()->ToString().c_str());
+ bt_log(INFO, "gap-le", "disconnecting link: %s", bt_str(*conn->link()));
CleanUpConnection(std::move(conn));
return true;
}
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.h b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.h
index 00f960a..11350f7 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.h
+++ b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager.h
@@ -138,8 +138,7 @@
}
// Disconnects any existing LE connection to |peer_id|, invalidating all
- // active LowEnergyConnectionRefs. Returns false if |peer_id| is not
- // recognized, the corresponding peer is not connected, or the peer can not be
+ // active LowEnergyConnectionRefs. Returns false if the peer can not be
// disconnected.
bool Disconnect(PeerId peer_id);
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager_unittest.cc b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager_unittest.cc
index 64364c8..aecae7c 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager_unittest.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/low_energy_connection_manager_unittest.cc
@@ -731,12 +731,17 @@
EXPECT_FALSE(conn_mgr()->Disconnect(dev1->identifier()));
}
-TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectError) {
+TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectUnknownPeer) {
+ // Unknown peers are inherently "not connected."
+ EXPECT_TRUE(conn_mgr()->Disconnect(PeerId(999)));
+}
+
+TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectUnconnectedPeer) {
auto* peer = peer_cache()->NewPeer(kAddress0, true);
test_device()->AddPeer(std::make_unique<FakePeer>(kAddress0));
- // This should fail as |peer0| is not connected.
- EXPECT_FALSE(conn_mgr()->Disconnect(peer->identifier()));
+ // This returns true so long the peer is not connected.
+ EXPECT_TRUE(conn_mgr()->Disconnect(peer->identifier()));
}
TEST_F(GAP_LowEnergyConnectionManagerTest, Disconnect) {
@@ -771,6 +776,41 @@
EXPECT_TRUE(canceled_peers().empty());
}
+TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectThrice) {
+ auto* peer = peer_cache()->NewPeer(kAddress0, true);
+ test_device()->AddPeer(std::make_unique<FakePeer>(kAddress0));
+
+ int closed_count = 0;
+ auto closed_cb = [&closed_count] { closed_count++; };
+
+ LowEnergyConnectionRefPtr conn_ref;
+ auto success_cb = [&closed_cb, &conn_ref](auto status, auto cb_conn_ref) {
+ EXPECT_TRUE(status);
+ conn_ref = std::move(cb_conn_ref);
+ ASSERT_TRUE(conn_ref);
+ conn_ref->set_closed_callback(closed_cb);
+ };
+
+ EXPECT_TRUE(conn_mgr()->Connect(peer->identifier(), success_cb));
+
+ RunLoopUntilIdle();
+
+ EXPECT_TRUE(conn_mgr()->Disconnect(peer->identifier()));
+
+ // Try to disconnect again while the first disconnection is in progress.
+ EXPECT_TRUE(conn_mgr()->Disconnect(peer->identifier()));
+
+ RunLoopUntilIdle();
+
+ // The single ref should get only one "closed" call.
+ EXPECT_EQ(1, closed_count);
+ EXPECT_TRUE(connected_peers().empty());
+ EXPECT_TRUE(canceled_peers().empty());
+
+ // Try to disconnect once more, now that the link is gone.
+ EXPECT_TRUE(conn_mgr()->Disconnect(peer->identifier()));
+}
+
// Tests when a link is lost without explicitly disconnecting
TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectEvent) {
auto* peer = peer_cache()->NewPeer(kAddress0, true);
@@ -804,6 +844,32 @@
EXPECT_EQ(2, closed_count);
}
+TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectAfterRefsReleased) {
+ auto* peer = peer_cache()->NewPeer(kAddress0, true);
+ test_device()->AddPeer(std::make_unique<FakePeer>(kAddress0));
+
+ LowEnergyConnectionRefPtr conn_ref;
+ auto success_cb = [&conn_ref](auto status, auto cb_conn_ref) {
+ EXPECT_TRUE(status);
+ conn_ref = std::move(cb_conn_ref);
+ };
+
+ EXPECT_TRUE(conn_mgr()->Connect(peer->identifier(), success_cb));
+
+ RunLoopUntilIdle();
+
+ ASSERT_TRUE(conn_ref);
+ conn_ref.reset();
+
+ // Try to disconnect while the zero-refs connection is being disconnected.
+ EXPECT_TRUE(conn_mgr()->Disconnect(peer->identifier()));
+
+ RunLoopUntilIdle();
+
+ EXPECT_TRUE(connected_peers().empty());
+ EXPECT_TRUE(canceled_peers().empty());
+}
+
TEST_F(GAP_LowEnergyConnectionManagerTest, DisconnectWhileRefPending) {
auto* peer = peer_cache()->NewPeer(kAddress0, true);
test_device()->AddPeer(std::make_unique<FakePeer>(kAddress0));