Prevent Bluetooth reconnects from blocking shutdown (#104150)

This commit is contained in:
J. Nick Koston 2023-11-19 08:22:26 -06:00 committed by GitHub
parent e7cec9b148
commit d3b4dd226b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 0 deletions

View File

@ -124,6 +124,7 @@ class BluetoothManager:
"storage", "storage",
"slot_manager", "slot_manager",
"_debug", "_debug",
"shutdown",
) )
def __init__( def __init__(
@ -165,6 +166,7 @@ class BluetoothManager:
self.storage = storage self.storage = storage
self.slot_manager = slot_manager self.slot_manager = slot_manager
self._debug = _LOGGER.isEnabledFor(logging.DEBUG) self._debug = _LOGGER.isEnabledFor(logging.DEBUG)
self.shutdown = False
@property @property
def supports_passive_scan(self) -> bool: def supports_passive_scan(self) -> bool:
@ -259,6 +261,7 @@ class BluetoothManager:
def async_stop(self, event: Event) -> None: def async_stop(self, event: Event) -> None:
"""Stop the Bluetooth integration at shutdown.""" """Stop the Bluetooth integration at shutdown."""
_LOGGER.debug("Stopping bluetooth manager") _LOGGER.debug("Stopping bluetooth manager")
self.shutdown = True
if self._cancel_unavailable_tracking: if self._cancel_unavailable_tracking:
self._cancel_unavailable_tracking() self._cancel_unavailable_tracking()
self._cancel_unavailable_tracking = None self._cancel_unavailable_tracking = None

View File

@ -270,6 +270,8 @@ class HaBleakClientWrapper(BleakClient):
"""Connect to the specified GATT server.""" """Connect to the specified GATT server."""
assert models.MANAGER is not None assert models.MANAGER is not None
manager = models.MANAGER manager = models.MANAGER
if manager.shutdown:
raise BleakError("Bluetooth is already shutdown")
if debug_logging := _LOGGER.isEnabledFor(logging.DEBUG): if debug_logging := _LOGGER.isEnabledFor(logging.DEBUG):
_LOGGER.debug("%s: Looking for backend to connect", self.__address) _LOGGER.debug("%s: Looking for backend to connect", self.__address)
wrapped_backend = self._async_get_best_available_backend_and_device(manager) wrapped_backend = self._async_get_best_available_backend_and_device(manager)

View File

@ -7,6 +7,7 @@ from unittest.mock import patch
import bleak import bleak
from bleak.backends.device import BLEDevice from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData from bleak.backends.scanner import AdvertisementData
from bleak.exc import BleakError
import pytest import pytest
from homeassistant.components.bluetooth import ( from homeassistant.components.bluetooth import (
@ -366,3 +367,25 @@ async def test_we_switch_adapters_on_failure(
assert await client.connect() is False assert await client.connect() is False
cancel_hci0() cancel_hci0()
cancel_hci1() cancel_hci1()
async def test_raise_after_shutdown(
hass: HomeAssistant,
two_adapters: None,
enable_bluetooth: None,
install_bleak_catcher,
mock_platform_client_that_raises_on_connect,
) -> None:
"""Ensure the slot gets released on connection exception."""
manager = _get_manager()
hci0_device_advs, cancel_hci0, cancel_hci1 = _generate_scanners_with_fake_devices(
hass
)
# hci0 has 2 slots, hci1 has 1 slot
with patch.object(manager, "shutdown", True):
ble_device = hci0_device_advs["00:00:00:00:00:01"][0]
client = bleak.BleakClient(ble_device)
with pytest.raises(BleakError, match="shutdown"):
await client.connect()
cancel_hci0()
cancel_hci1()