Make Bluetooth active coordinator debouncers run tasks in the background (#113129)

This commit is contained in:
J. Nick Koston 2024-03-12 07:43:43 -10:00 committed by GitHub
parent 4c2a54746d
commit c948392ebc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 33 additions and 32 deletions

View File

@ -99,6 +99,7 @@ class ActiveBluetoothDataUpdateCoordinator(
cooldown=POLL_DEFAULT_COOLDOWN,
immediate=POLL_DEFAULT_IMMEDIATE,
function=self._async_poll,
background=True,
)
else:
poll_debouncer.function = self._async_poll

View File

@ -92,6 +92,7 @@ class ActiveBluetoothProcessorCoordinator(
cooldown=POLL_DEFAULT_COOLDOWN,
immediate=POLL_DEFAULT_IMMEDIATE,
function=self._async_poll,
background=True,
)
else:
poll_debouncer.function = self._async_poll

View File

@ -129,7 +129,7 @@ async def test_basic_usage(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
assert coordinator.data == {"fake": "data"}
@ -175,13 +175,13 @@ async def test_bleak_error_during_polling(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
assert coordinator.data is None
assert coordinator.last_poll_successful is False
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
assert coordinator.data == {"fake": "data"}
assert coordinator.last_poll_successful is True
@ -228,13 +228,13 @@ async def test_generic_exception_during_polling(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
assert coordinator.data is None
assert coordinator.last_poll_successful is False
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
assert coordinator.data == {"fake": "data"}
assert coordinator.last_poll_successful is True
@ -280,7 +280,7 @@ async def test_polling_debounce(
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
# We should only get one poll because of the debounce
assert coordinator.data == {"poll_count": 1}
@ -316,7 +316,9 @@ async def test_polling_debounce_with_custom_debouncer(
mode=BluetoothScanningMode.ACTIVE,
needs_poll_method=_needs_poll,
poll_method=_poll_method,
poll_debouncer=Debouncer(hass, _LOGGER, cooldown=0.1, immediate=True),
poll_debouncer=Debouncer(
hass, _LOGGER, cooldown=0.1, immediate=True, background=True
),
)
assert coordinator.available is False # no data yet
@ -327,7 +329,7 @@ async def test_polling_debounce_with_custom_debouncer(
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
# We should only get one poll because of the debounce
assert coordinator.data == {"poll_count": 1}
@ -371,25 +373,25 @@ async def test_polling_rejecting_the_first_time(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
# First poll is rejected, so no data yet
assert coordinator.data is None
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
# Data is the same so no poll check
assert coordinator.data is None
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
# Data is different so poll is done
assert coordinator.data == {"fake": "data"}
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
# Data is different again so poll is done
assert coordinator.data == {"fake": "data"}
@ -434,19 +436,19 @@ async def test_no_polling_after_stop_event(
assert needs_poll_calls == 0
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
assert coordinator.data == {"fake": "data"}
assert needs_poll_calls == 1
hass.set_state(CoreState.stopping)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert needs_poll_calls == 1
# Should not generate a poll now
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert needs_poll_calls == 1
cancel()

View File

@ -84,7 +84,7 @@ async def test_basic_usage(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert coordinator.available is True
@ -127,10 +127,7 @@ async def test_poll_can_be_skipped(
needs_poll_method=_poll_needed,
poll_method=_poll,
poll_debouncer=Debouncer(
hass,
_LOGGER,
cooldown=0,
immediate=True,
hass, _LOGGER, cooldown=0, immediate=True, background=True
),
)
assert coordinator.available is False # no data yet
@ -142,19 +139,19 @@ async def test_poll_can_be_skipped(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
flag = False
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, True)
flag = True
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
cancel()
@ -208,7 +205,7 @@ async def test_bleak_error_and_recover(
# First poll fails
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
assert (
@ -219,7 +216,7 @@ async def test_bleak_error_and_recover(
# Second poll works
flag = False
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
cancel()
@ -272,13 +269,13 @@ async def test_poll_failure_and_recover(
# First poll fails
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
# Second poll works
flag = False
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
cancel()
@ -329,7 +326,7 @@ async def test_second_poll_needed(
# Second poll gets stuck behind first poll
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
cancel()
@ -381,7 +378,7 @@ async def test_rate_limit(
# Third poll gets stuck behind first poll doesn't get queued
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert async_handle_update.mock_calls[-1] == call({"testdata": 1})
cancel()
@ -425,7 +422,7 @@ async def test_no_polling_after_stop_event(
cancel = coordinator.async_start()
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert needs_poll_calls == 1
assert coordinator.available is True
@ -438,12 +435,12 @@ async def test_no_polling_after_stop_event(
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
hass.set_state(CoreState.stopping)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert needs_poll_calls == 1
# Should not generate a poll now that CoreState is stopping
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert needs_poll_calls == 1
cancel()