Add startup timeout to bluetooth (#75848)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
J. Nick Koston
2022-07-28 11:14:13 -10:00
committed by Franck Nijhof
parent 53870dd0bc
commit e4e36b51b6
2 changed files with 38 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
"""The bluetooth integration."""
from __future__ import annotations
import asyncio
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime, timedelta
@@ -8,6 +9,7 @@ from enum import Enum
import logging
from typing import Final, Union
import async_timeout
from bleak import BleakError
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
@@ -43,6 +45,7 @@ _LOGGER = logging.getLogger(__name__)
UNAVAILABLE_TRACK_SECONDS: Final = 60 * 5
START_TIMEOUT = 15
SOURCE_LOCAL: Final = "local"
@@ -300,7 +303,13 @@ class BluetoothManager:
self._device_detected, {}
)
try:
await self.scanner.start()
async with async_timeout.timeout(START_TIMEOUT):
await self.scanner.start()
except asyncio.TimeoutError as ex:
self._cancel_device_detected()
raise ConfigEntryNotReady(
f"Timed out starting Bluetooth after {START_TIMEOUT} seconds"
) from ex
except (FileNotFoundError, BleakError) as ex:
self._cancel_device_detected()
raise ConfigEntryNotReady(f"Failed to start Bluetooth: {ex}") from ex

View File

@@ -1,4 +1,5 @@
"""Tests for the Bluetooth integration."""
import asyncio
from datetime import timedelta
from unittest.mock import MagicMock, patch
@@ -95,6 +96,33 @@ async def test_setup_and_stop_broken_bluetooth(hass, caplog):
assert len(bluetooth.async_discovered_service_info(hass)) == 0
async def test_setup_and_stop_broken_bluetooth_hanging(hass, caplog):
"""Test we fail gracefully when bluetooth/dbus is hanging."""
mock_bt = []
async def _mock_hang():
await asyncio.sleep(1)
with patch.object(bluetooth, "START_TIMEOUT", 0), patch(
"homeassistant.components.bluetooth.HaBleakScanner.async_setup"
), patch(
"homeassistant.components.bluetooth.HaBleakScanner.start",
side_effect=_mock_hang,
), patch(
"homeassistant.components.bluetooth.async_get_bluetooth", return_value=mock_bt
):
assert await async_setup_component(
hass, bluetooth.DOMAIN, {bluetooth.DOMAIN: {}}
)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
await hass.async_block_till_done()
assert "Timed out starting Bluetooth" in caplog.text
async def test_setup_and_retry_adapter_not_yet_available(hass, caplog):
"""Test we retry if the adapter is not yet available."""
mock_bt = []