Mark executor jobs as background unless created from a tracked task (#114450)

* Mark executor jobs as background unless created from a tracked task

If the current task is not tracked the executor job should not
be a background task to avoid delaying startup and shutdown.

Currently any executor job created in a untracked task or
background task would end up being tracked and delaying
startup/shutdown

* import exec has the same issue

* Avoid tracking import executor jobs

There is no reason to track these jobs as they are always awaited
and we do not want to support fire and forget import executor jobs

* fix xiaomi_miio

* lots of fire time changed without background await

* revert changes moved to other PR

* more

* more

* more

* m

* m

* p

* fix fire and forget tests

* scrape

* sonos

* system

* more

* capture callback before block

* coverage

* more

* more races

* more races

* more

* missed some

* more fixes

* missed some more

* fix

* remove unneeded

* one more race

* two
pull/114468/head
J. Nick Koston 2024-03-29 18:16:53 -10:00 committed by GitHub
parent aec7a67a58
commit 9a79320861
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 246 additions and 180 deletions

View File

@ -774,8 +774,11 @@ class HomeAssistant:
) -> asyncio.Future[_T]:
"""Add an executor job from within the event loop."""
task = self.loop.run_in_executor(None, target, *args)
self._tasks.add(task)
task.add_done_callback(self._tasks.remove)
tracked = asyncio.current_task() in self._tasks
task_bucket = self._tasks if tracked else self._background_tasks
task_bucket.add(task)
task.add_done_callback(task_bucket.remove)
return task

View File

@ -201,7 +201,7 @@ async def test_sensor_dark(hass: HomeAssistant, freezer: FrozenDateTimeFactory)
):
freezer.tick(SCAN_INTERVAL * 2)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
power = hass.states.get("sensor.mydevicename_total_energy")
assert power.state == "unknown"
# sun rose again
@ -218,7 +218,7 @@ async def test_sensor_dark(hass: HomeAssistant, freezer: FrozenDateTimeFactory)
):
freezer.tick(SCAN_INTERVAL * 4)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
power = hass.states.get("sensor.mydevicename_power_output")
assert power is not None
assert power.state == "45.7"
@ -237,7 +237,7 @@ async def test_sensor_dark(hass: HomeAssistant, freezer: FrozenDateTimeFactory)
):
freezer.tick(SCAN_INTERVAL * 6)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
power = hass.states.get("sensor.mydevicename_power_output")
assert power.state == "unknown" # should this be 'available'?
@ -277,7 +277,7 @@ async def test_sensor_unknown_error(
):
freezer.tick(SCAN_INTERVAL * 2)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert (
"Exception: AuroraError('another error') occurred, 2 retries remaining"
in caplog.text

View File

@ -278,7 +278,7 @@ async def test_known_hosts(hass: HomeAssistant, castbrowser_mock) -> None:
result["flow_id"], {"known_hosts": "192.168.0.1, 192.168.0.2"}
)
assert result["type"] == "create_entry"
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
config_entry = hass.config_entries.async_entries("cast")[0]
assert castbrowser_mock.return_value.start_discovery.call_count == 1
@ -291,7 +291,7 @@ async def test_known_hosts(hass: HomeAssistant, castbrowser_mock) -> None:
user_input={"known_hosts": "192.168.0.11, 192.168.0.12"},
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
castbrowser_mock.return_value.start_discovery.assert_not_called()
castbrowser_mock.assert_not_called()

View File

@ -137,8 +137,8 @@ async def async_setup_cast_internal_discovery(hass, config=None):
return_value=browser,
) as cast_browser:
add_entities = await async_setup_cast(hass, config)
await hass.async_block_till_done()
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
await hass.async_block_till_done(wait_background_tasks=True)
assert browser.start_discovery.call_count == 1
@ -209,8 +209,8 @@ async def async_setup_media_player_cast(hass: HomeAssistant, info: ChromecastInf
entry = MockConfigEntry(data=data, domain="cast")
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
await hass.async_block_till_done(wait_background_tasks=True)
discovery_callback = cast_browser.call_args[0][0].add_cast

View File

@ -199,7 +199,7 @@ async def test_image_update_unavailable(
# fritzbox becomes unavailable
fc_class_mock().call_action_side_effect(ReadTimeout)
async_fire_time_changed(hass, utcnow() + timedelta(seconds=60))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("image.mock_title_guestwifi")
assert state.state == STATE_UNKNOWN
@ -207,7 +207,7 @@ async def test_image_update_unavailable(
# fritzbox is available again
fc_class_mock().call_action_side_effect(None)
async_fire_time_changed(hass, utcnow() + timedelta(seconds=60))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("image.mock_title_guestwifi")
assert state.state != STATE_UNKNOWN

View File

@ -134,7 +134,7 @@ async def test_sensor_update_fail(
fc_class_mock().call_action_side_effect(FritzConnectionException)
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=300))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
sensors = hass.states.async_all(SENSOR_DOMAIN)
for sensor in sensors:

View File

@ -104,7 +104,7 @@ async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 2
assert fritz().login.call_count == 1
@ -123,7 +123,7 @@ async def test_update_error(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 2
assert fritz().login.call_count == 1
@ -146,7 +146,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_device_alarm")
assert state

View File

@ -65,7 +65,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_template")
assert state

View File

@ -145,7 +145,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_next_scheduled_preset")
assert state
@ -203,7 +203,7 @@ async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert fritz().update_devices.call_count == 2
@ -243,7 +243,7 @@ async def test_update_error(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 4
assert fritz().login.call_count == 4
@ -386,7 +386,7 @@ async def test_preset_mode_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert fritz().update_devices.call_count == 2
@ -397,7 +397,7 @@ async def test_preset_mode_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert fritz().update_devices.call_count == 3
@ -422,7 +422,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_climate")
assert state

View File

@ -108,7 +108,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_climate")
assert state

View File

@ -237,7 +237,7 @@ async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 2
assert fritz().login.call_count == 1
@ -259,7 +259,7 @@ async def test_update_error(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 4
assert fritz().login.call_count == 4
@ -294,7 +294,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_light")
assert state

View File

@ -87,7 +87,7 @@ async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 2
assert fritz().login.call_count == 1
@ -105,7 +105,7 @@ async def test_update_error(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 4
assert fritz().login.call_count == 4
@ -128,7 +128,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_device_temperature")
assert state

View File

@ -151,7 +151,7 @@ async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 2
assert fritz().login.call_count == 1
@ -169,7 +169,7 @@ async def test_update_error(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert fritz().update_devices.call_count == 4
assert fritz().login.call_count == 4
@ -207,7 +207,7 @@ async def test_discover_new_device(hass: HomeAssistant, fritz: Mock) -> None:
next_update = dt_util.utcnow() + timedelta(seconds=200)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(f"{DOMAIN}.new_switch")
assert state

View File

@ -99,7 +99,7 @@ async def test_setup(
# so no changes to entities.
mock_feed.return_value.update.return_value = "OK_NO_DATA", None
async_fire_time_changed(hass, utcnow + geo_rss_events.SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all()
assert len(all_states) == 1
@ -109,7 +109,7 @@ async def test_setup(
# Simulate an update - empty data, removes all entities
mock_feed.return_value.update.return_value = "ERROR", None
async_fire_time_changed(hass, utcnow + 2 * geo_rss_events.SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
all_states = hass.states.async_all()
assert len(all_states) == 1

View File

@ -46,7 +46,7 @@ async def test_sensors(
):
next_update = dt_util.utcnow() + timedelta(minutes=15)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(SENSOR)
assert state.state == result
@ -61,7 +61,7 @@ async def test_sensor_reauth_trigger(
with patch(TOKEN, side_effect=RefreshError):
next_update = dt_util.utcnow() + timedelta(minutes=15)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
flows = hass.config_entries.flow.async_progress()

View File

@ -43,7 +43,7 @@ async def test_window_shuttler(
windowshutter.is_open = False
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF
@ -68,12 +68,12 @@ async def test_window_shuttler_battery(
windowshutter.battery = 1 # maxcube-api MAX_DEVICE_BATTERY_LOW
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(BATTERY_ENTITY_ID)
assert state.state == STATE_ON # on means low
windowshutter.battery = 0 # maxcube-api MAX_DEVICE_BATTERY_OK
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(BATTERY_ENTITY_ID)
assert state.state == STATE_OFF # off means normal

View File

@ -140,7 +140,7 @@ async def test_thermostat_set_hvac_mode_off(
thermostat.valve_position = 0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.OFF
@ -168,8 +168,8 @@ async def test_thermostat_set_hvac_mode_heat(
thermostat.mode = MAX_DEVICE_MODE_MANUAL
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -204,7 +204,7 @@ async def test_thermostat_set_temperature(
thermostat.valve_position = 0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.AUTO
@ -248,7 +248,7 @@ async def test_thermostat_set_preset_on(
thermostat.target_temperature = ON_TEMPERATURE
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -273,7 +273,7 @@ async def test_thermostat_set_preset_comfort(
thermostat.target_temperature = thermostat.comfort_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -298,7 +298,7 @@ async def test_thermostat_set_preset_eco(
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -323,7 +323,7 @@ async def test_thermostat_set_preset_away(
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -348,7 +348,7 @@ async def test_thermostat_set_preset_boost(
thermostat.target_temperature = thermostat.eco_temperature
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == HVACMode.AUTO
@ -401,7 +401,7 @@ async def test_wallthermostat_set_hvac_mode_heat(
wallthermostat.target_temperature = MIN_TEMPERATURE
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(WALL_ENTITY_ID)
assert state.state == HVACMode.HEAT
@ -425,7 +425,7 @@ async def test_wallthermostat_set_hvac_mode_auto(
wallthermostat.target_temperature = 23.0
async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(WALL_ENTITY_ID)
assert state.state == HVACMode.AUTO

View File

@ -125,7 +125,7 @@ async def test_site_cannot_update(
future_time = utcnow() + timedelta(minutes=20)
async_fire_time_changed(hass, future_time)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
weather = hass.states.get("weather.met_office_wavertree_daily")
assert weather.state == STATE_UNAVAILABLE
@ -297,7 +297,7 @@ async def test_forecast_service(
# Trigger data refetch
freezer.tick(DEFAULT_SCAN_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert wavertree_data["wavertree_daily_mock"].call_count == 2
assert wavertree_data["wavertree_hourly_mock"].call_count == 1
@ -324,7 +324,7 @@ async def test_forecast_service(
freezer.tick(DEFAULT_SCAN_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
response = await hass.services.async_call(
WEATHER_DOMAIN,
@ -412,7 +412,7 @@ async def test_forecast_subscription(
freezer.tick(DEFAULT_SCAN_INTERVAL + timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
msg = await client.receive_json()
assert msg["id"] == subscription_id
@ -430,6 +430,6 @@ async def test_forecast_subscription(
)
freezer.tick(timedelta(seconds=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
msg = await client.receive_json()
assert msg["success"]

View File

@ -88,7 +88,7 @@ async def test_device_trackers(
WIRELESS_DATA.append(DEVICE_2_WIRELESS)
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
device_2 = hass.states.get("device_tracker.device_2")
assert device_2
@ -101,7 +101,7 @@ async def test_device_trackers(
del WIRELESS_DATA[1] # device 2 is removed from wireless list
with freeze_time(utcnow() + timedelta(minutes=4)):
async_fire_time_changed(hass, utcnow() + timedelta(minutes=4))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
device_2 = hass.states.get("device_tracker.device_2")
assert device_2
@ -110,7 +110,7 @@ async def test_device_trackers(
# test state changes to away if last_seen past consider_home_interval
with freeze_time(utcnow() + timedelta(minutes=6)):
async_fire_time_changed(hass, utcnow() + timedelta(minutes=6))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
device_2 = hass.states.get("device_tracker.device_2")
assert device_2
@ -266,7 +266,7 @@ async def test_update_failed(hass: HomeAssistant, mock_device_registry_devices)
mikrotik.hub.MikrotikData, "command", side_effect=mikrotik.errors.CannotConnect
):
async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
device_1 = hass.states.get("device_tracker.device_1")
assert device_1

View File

@ -183,7 +183,7 @@ async def test_service_calls_with_entity_id(hass: HomeAssistant) -> None:
# Restoring other media player to its previous state
# The zone should not be restored
await _call_monoprice_service(hass, SERVICE_RESTORE, {"entity_id": ZONE_2_ID})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# Checking that values were not (!) restored
state = hass.states.get(ZONE_1_ID)
@ -193,7 +193,7 @@ async def test_service_calls_with_entity_id(hass: HomeAssistant) -> None:
# Restoring media player to its previous state
await _call_monoprice_service(hass, SERVICE_RESTORE, {"entity_id": ZONE_1_ID})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -226,7 +226,7 @@ async def test_service_calls_with_all_entities(hass: HomeAssistant) -> None:
# Restoring media player to its previous state
await _call_monoprice_service(hass, SERVICE_RESTORE, {"entity_id": "all"})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -259,7 +259,7 @@ async def test_service_calls_without_relevant_entities(hass: HomeAssistant) -> N
# Restoring media player to its previous state
await _call_monoprice_service(hass, SERVICE_RESTORE, {"entity_id": "light.demo"})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -273,7 +273,7 @@ async def test_restore_without_snapshort(hass: HomeAssistant) -> None:
with patch.object(MockMonoprice, "restore_zone") as method_call:
await _call_monoprice_service(hass, SERVICE_RESTORE, {"entity_id": ZONE_1_ID})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert not method_call.called
@ -295,7 +295,7 @@ async def test_update(hass: HomeAssistant) -> None:
monoprice.set_volume(11, 38)
await async_update_entity(hass, ZONE_1_ID)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -321,7 +321,7 @@ async def test_failed_update(hass: HomeAssistant) -> None:
with patch.object(MockMonoprice, "zone_status", side_effect=SerialException):
await async_update_entity(hass, ZONE_1_ID)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -347,7 +347,7 @@ async def test_empty_update(hass: HomeAssistant) -> None:
with patch.object(MockMonoprice, "zone_status", return_value=None):
await async_update_entity(hass, ZONE_1_ID)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -418,7 +418,7 @@ async def test_unknown_source(hass: HomeAssistant) -> None:
monoprice.set_source(11, 5)
await async_update_entity(hass, ZONE_1_ID)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)

View File

@ -23,7 +23,7 @@ async def test_media_player_handle_URLerror(
mock_remote.get_mute = Mock(side_effect=URLError(None, None))
async_fire_time_changed(hass, utcnow() + timedelta(minutes=2))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state_tv = hass.states.get("media_player.panasonic_viera_tv")
assert state_tv.state == STATE_UNAVAILABLE
@ -41,7 +41,7 @@ async def test_media_player_handle_HTTPError(
mock_remote.get_mute = Mock(side_effect=HTTPError(None, 400, None, None, None))
async_fire_time_changed(hass, utcnow() + timedelta(minutes=2))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state_tv = hass.states.get("media_player.panasonic_viera_tv")
assert state_tv.state == STATE_OFF

View File

@ -208,7 +208,7 @@ async def test_update_unavailable(projector_from_address, hass: HomeAssistant) -
projector_from_address.side_effect = socket.timeout
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("media_player.test")
assert state.state == "unavailable"
@ -237,7 +237,7 @@ async def test_unavailable_time(mocked_projector, hass: HomeAssistant) -> None:
mocked_projector.get_power.side_effect = ProjectorError("unavailable time")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("media_player.test")
assert state.state == "off"

View File

@ -332,7 +332,7 @@ async def test_log_object_sources(
caplog.clear()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=11))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "No new object growth found" in caplog.text
fake_object2 = FakeObject()
@ -344,7 +344,7 @@ async def test_log_object_sources(
caplog.clear()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=21))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "New object FakeObject (1/2)" in caplog.text
many_objects = [FakeObject() for _ in range(30)]
@ -352,7 +352,7 @@ async def test_log_object_sources(
caplog.clear()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "New object FakeObject (2/30)" in caplog.text
assert "New objects overflowed by {'FakeObject': 25}" in caplog.text
@ -362,7 +362,7 @@ async def test_log_object_sources(
caplog.clear()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=41))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "FakeObject" not in caplog.text
assert "No new object growth found" not in caplog.text
@ -370,7 +370,7 @@ async def test_log_object_sources(
await hass.async_block_till_done()
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=51))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "FakeObject" not in caplog.text
assert "No new object growth found" not in caplog.text

View File

@ -234,6 +234,7 @@ async def test_media_attributes_are_fetched(hass: HomeAssistant) -> None:
with patch(mock_func, return_value=mock_result) as mock_fetch:
await mock_ddp_response(hass, MOCK_STATUS_PLAYING)
await hass.async_block_till_done(wait_background_tasks=True)
mock_state = hass.states.get(mock_entity_id)
mock_attrs = dict(mock_state.attributes)
@ -255,6 +256,7 @@ async def test_media_attributes_are_fetched(hass: HomeAssistant) -> None:
with patch(mock_func, return_value=mock_result) as mock_fetch_app:
await mock_ddp_response(hass, MOCK_STATUS_PLAYING)
await hass.async_block_till_done(wait_background_tasks=True)
mock_state = hass.states.get(mock_entity_id)
mock_attrs = dict(mock_state.attributes)

View File

@ -78,7 +78,7 @@ hass.states.set('test.entity', data.get('name', 'not set'))
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {"name": "paulus"})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state("test.entity", "paulus")
@ -96,7 +96,7 @@ print("This triggers warning.")
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "Don't use print() inside scripts." in caplog.text
@ -111,7 +111,7 @@ logger.info('Logging from inside script')
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "Logging from inside script" in caplog.text
@ -126,7 +126,7 @@ this is not valid Python
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "Error loading script test.py" in caplog.text
@ -140,8 +140,8 @@ async def test_execute_runtime_error(
raise Exception('boom')
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done(wait_background_tasks=True)
assert "Error executing script" in caplog.text
@ -153,7 +153,7 @@ raise Exception('boom')
"""
task = hass.async_add_executor_job(execute, hass, "test.py", source, {}, True)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert type(task.exception()) == HomeAssistantError
assert "Error executing script (Exception): boom" in str(task.exception())
@ -168,7 +168,7 @@ async def test_accessing_async_methods(
hass.async_stop()
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
assert "Not allowed to access async methods" in caplog.text
@ -181,7 +181,7 @@ hass.async_stop()
"""
task = hass.async_add_executor_job(execute, hass, "test.py", source, {}, True)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert type(task.exception()) == ServiceValidationError
assert "Not allowed to access async methods" in str(task.exception())
@ -198,7 +198,7 @@ mylist = [1, 2, 3, 4]
logger.info('Logging from inside script: %s %s' % (mydict["a"], mylist[2]))
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
assert "Logging from inside script: 1 3" in caplog.text
@ -217,7 +217,7 @@ async def test_accessing_forbidden_methods(
"time.tzset()": "TimeWrapper.tzset",
}.items():
caplog.records.clear()
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
assert f"Not allowed to access {name}" in caplog.text
@ -231,7 +231,7 @@ async def test_accessing_forbidden_methods_with_response(hass: HomeAssistant) ->
"time.tzset()": "TimeWrapper.tzset",
}.items():
task = hass.async_add_executor_job(execute, hass, "test.py", source, {}, True)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert type(task.exception()) == ServiceValidationError
assert f"Not allowed to access {name}" in str(task.exception())
@ -244,7 +244,7 @@ for i in [1, 2]:
hass.states.set('hello.{}'.format(i), 'world')
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
assert hass.states.is_state("hello.1", "world")
@ -279,7 +279,7 @@ hass.states.set('hello.ab_list', '{}'.format(ab_list))
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state("hello.a", "1")
assert hass.states.is_state("hello.b", "2")
@ -302,7 +302,7 @@ hass.states.set('hello.b', a[1])
hass.states.set('hello.c', a[2])
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state("hello.a", "1")
assert hass.states.is_state("hello.b", "2")
@ -325,7 +325,7 @@ hass.states.set('module.datetime',
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state("module.time", "1986")
assert hass.states.is_state("module.time_strptime", "12:34")
@ -351,7 +351,7 @@ def b():
b()
"""
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state("hello.a", "one")
assert hass.states.is_state("hello.b", "two")
@ -517,7 +517,7 @@ time.sleep(5)
with patch("homeassistant.components.python_script.time.sleep"):
hass.async_add_executor_job(execute, hass, "test.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert caplog.text.count("time.sleep") == 1
@ -664,7 +664,7 @@ hass.states.set('hello.c', c)
"""
hass.async_add_executor_job(execute, hass, "aug_assign.py", source, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get("hello.a").state == str(((10 + 20) * 5) - 8)
assert hass.states.get("hello.b").state == ("foo" + "bar") * 2
@ -686,5 +686,5 @@ async def test_prohibited_augmented_assignment_operations(
) -> None:
"""Test that prohibited augmented assignment operations raise an error."""
hass.async_add_executor_job(execute, hass, "aug_assign_prohibited.py", case, {})
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert error in caplog.text

View File

@ -200,7 +200,7 @@ async def test_setup_websocket_2(
next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(entity_id)
assert state
@ -225,7 +225,7 @@ async def test_setup_encrypted_websocket(
next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state
@ -242,7 +242,7 @@ async def test_update_on(
next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_ON
@ -262,7 +262,7 @@ async def test_update_off(
next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_UNAVAILABLE
@ -290,7 +290,7 @@ async def test_update_off_ws_no_power_state(
next_update = mock_now + timedelta(minutes=5)
freezer.move_to(next_update)
async_fire_time_changed(hass, next_update)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ENTITY_ID)
assert state.state == STATE_OFF

View File

@ -22,7 +22,7 @@ async def test_keypad_disabled_binary_sensor(
# Make the coordinator refresh data.
async_fire_time_changed(hass, utcnow() + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
keypad = hass.states.get("binary_sensor.vault_door_keypad_disabled")
assert keypad is not None
@ -43,7 +43,7 @@ async def test_keypad_disabled_binary_sensor_use_previous_logs_on_failure(
# Make the coordinator refresh data.
async_fire_time_changed(hass, utcnow() + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
keypad = hass.states.get("binary_sensor.vault_door_keypad_disabled")
assert keypad is not None

View File

@ -59,7 +59,7 @@ async def test_changed_by(
# Make the coordinator refresh data.
async_fire_time_changed(hass, utcnow() + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
mock_lock.last_changed_by.assert_called_once_with()
lock_device = hass.states.get("lock.vault_door")

View File

@ -261,7 +261,7 @@ async def test_scrape_sensor_no_data_refresh(hass: HomeAssistant) -> None:
mocker.payload = "test_scrape_sensor_no_data"
async_fire_time_changed(hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.ha_version")
assert state is not None
@ -541,7 +541,7 @@ async def test_templates_with_yaml(hass: HomeAssistant) -> None:
hass,
dt_util.utcnow() + timedelta(minutes=10),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template")
assert state.state == "Current Version: 2021.12.10"
@ -555,7 +555,7 @@ async def test_templates_with_yaml(hass: HomeAssistant) -> None:
hass,
dt_util.utcnow() + timedelta(minutes=20),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template")
assert state.state == STATE_UNAVAILABLE
@ -568,7 +568,7 @@ async def test_templates_with_yaml(hass: HomeAssistant) -> None:
hass,
dt_util.utcnow() + timedelta(minutes=30),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.get_values_with_template")
assert state.state == "Current Version: 2021.12.10"
@ -608,7 +608,7 @@ async def test_availability(
hass.states.async_set("sensor.input1", "on")
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.current_version")
assert state.state == "2021.12.10"
@ -618,7 +618,7 @@ async def test_availability(
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.current_version")
assert state.state == STATE_UNAVAILABLE

View File

@ -53,7 +53,7 @@ async def test_solaredgeoverviewdataservice_energy_values_validity(
mock_solaredge().get_overview.return_value = mock_overview_data
freezer.tick(OVERVIEW_UPDATE_DELAY)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.solaredge_lifetime_energy")
assert state
assert state.state == str(mock_overview_data["overview"]["lifeTimeData"]["energy"])
@ -63,7 +63,7 @@ async def test_solaredgeoverviewdataservice_energy_values_validity(
mock_solaredge().get_overview.return_value = mock_overview_data
freezer.tick(OVERVIEW_UPDATE_DELAY)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.solaredge_lifetime_energy")
assert state
@ -74,7 +74,7 @@ async def test_solaredgeoverviewdataservice_energy_values_validity(
mock_solaredge().get_overview.return_value = mock_overview_data
freezer.tick(OVERVIEW_UPDATE_DELAY)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.solaredge_lifetime_energy")
assert state
@ -85,7 +85,7 @@ async def test_solaredgeoverviewdataservice_energy_values_validity(
mock_solaredge().get_overview.return_value = mock_overview_data
freezer.tick(OVERVIEW_UPDATE_DELAY)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.solaredge_energy_this_year")
assert state
@ -103,7 +103,7 @@ async def test_solaredgeoverviewdataservice_energy_values_validity(
mock_solaredge().get_overview.return_value = mock_overview_data
freezer.tick(OVERVIEW_UPDATE_DELAY)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.solaredge_lifetime_energy")
assert state

View File

@ -94,8 +94,9 @@ def async_setup_sonos(hass, config_entry, fire_zgs_event):
async def _wrapper():
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
await fire_zgs_event()
await hass.async_block_till_done(wait_background_tasks=True)
return _wrapper

View File

@ -28,10 +28,12 @@ async def test_subscription_repair_issues(
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
await hass.async_block_till_done()
# Ensure an issue is registered on subscription failure
sub_callback = subscription.callback
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert issue_registry.async_get_issue(DOMAIN, SUB_FAIL_ISSUE_ID)
# Ensure the issue still exists after reload
@ -42,7 +44,6 @@ async def test_subscription_repair_issues(
# Ensure the issue has been removed after a successful subscription callback
variables = {"ZoneGroupState": zgs_discovery}
event = SonosMockEvent(soco, soco.zoneGroupTopology, variables)
sub_callback = subscription.callback
sub_callback(event)
await hass.async_block_till_done()
assert not issue_registry.async_get_issue(DOMAIN, SUB_FAIL_ISSUE_ID)

View File

@ -26,6 +26,7 @@ async def test_entity_registry_unsupported(
soco.get_battery_info.side_effect = NotSupportedException
await async_setup_sonos()
await hass.async_block_till_done(wait_background_tasks=True)
assert "media_player.zone_a" in entity_registry.entities
assert "sensor.zone_a_battery" not in entity_registry.entities
@ -36,6 +37,8 @@ async def test_entity_registry_supported(
hass: HomeAssistant, async_autosetup_sonos, soco, entity_registry: er.EntityRegistry
) -> None:
"""Test sonos device with battery registered in the device registry."""
await hass.async_block_till_done(wait_background_tasks=True)
assert "media_player.zone_a" in entity_registry.entities
assert "sensor.zone_a_battery" in entity_registry.entities
assert "binary_sensor.zone_a_charging" in entity_registry.entities
@ -69,6 +72,7 @@ async def test_battery_on_s1(
soco.get_battery_info.return_value = {}
await async_setup_sonos()
await hass.async_block_till_done(wait_background_tasks=True)
subscription = soco.deviceProperties.subscribe.return_value
sub_callback = subscription.callback
@ -78,7 +82,7 @@ async def test_battery_on_s1(
# Update the speaker with a callback event
sub_callback(device_properties_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
battery = entity_registry.entities["sensor.zone_a_battery"]
battery_state = hass.states.get(battery.entity_id)
@ -101,6 +105,7 @@ async def test_device_payload_without_battery(
soco.get_battery_info.return_value = None
await async_setup_sonos()
await hass.async_block_till_done(wait_background_tasks=True)
subscription = soco.deviceProperties.subscribe.return_value
sub_callback = subscription.callback
@ -109,7 +114,7 @@ async def test_device_payload_without_battery(
device_properties_event.variables["more_info"] = bad_payload
sub_callback(device_properties_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert bad_payload in caplog.text
@ -125,6 +130,7 @@ async def test_device_payload_without_battery_and_ignored_keys(
soco.get_battery_info.return_value = None
await async_setup_sonos()
await hass.async_block_till_done(wait_background_tasks=True)
subscription = soco.deviceProperties.subscribe.return_value
sub_callback = subscription.callback
@ -133,7 +139,7 @@ async def test_device_payload_without_battery_and_ignored_keys(
device_properties_event.variables["more_info"] = ignored_payload
sub_callback(device_properties_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert ignored_payload not in caplog.text
@ -150,7 +156,7 @@ async def test_audio_input_sensor(
subscription = soco.avTransport.subscribe.return_value
sub_callback = subscription.callback
sub_callback(tv_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
audio_input_sensor = entity_registry.entities["sensor.zone_a_audio_input_format"]
audio_input_state = hass.states.get(audio_input_sensor.entity_id)
@ -161,7 +167,7 @@ async def test_audio_input_sensor(
type(soco).soundbar_audio_input_format = no_input_mock
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
no_input_mock.assert_called_once()
audio_input_state = hass.states.get(audio_input_sensor.entity_id)
@ -169,13 +175,13 @@ async def test_audio_input_sensor(
# Ensure state is not polled when source is not TV and state is already "No input"
sub_callback(no_media_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
unpolled_mock = PropertyMock(return_value="Will not be polled")
type(soco).soundbar_audio_input_format = unpolled_mock
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
unpolled_mock.assert_not_called()
audio_input_state = hass.states.get(audio_input_sensor.entity_id)
@ -199,7 +205,7 @@ async def test_microphone_binary_sensor(
# Update the speaker with a callback event
subscription = soco.deviceProperties.subscribe.return_value
subscription.callback(device_properties_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
mic_binary_sensor_state = hass.states.get(mic_binary_sensor.entity_id)
assert mic_binary_sensor_state.state == STATE_ON
@ -225,17 +231,18 @@ async def test_favorites_sensor(
empty_event = SonosMockEvent(soco, service, {})
subscription = service.subscribe.return_value
subscription.callback(event=empty_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# Reload the integration to enable the sensor
async_fire_time_changed(
hass,
dt_util.utcnow() + timedelta(seconds=RELOAD_AFTER_UPDATE_DELAY + 1),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# Trigger subscription callback for speaker discovery
await fire_zgs_event()
await hass.async_block_till_done(wait_background_tasks=True)
favorites_updated_event = SonosMockEvent(
soco, service, {"favorites_update_id": "2", "container_update_i_ds": "FV:2,2"}
@ -245,4 +252,4 @@ async def test_favorites_sensor(
return_value=True,
):
subscription.callback(event=favorites_updated_event)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)

View File

@ -12,9 +12,20 @@ from tests.common import async_fire_time_changed
async def test_fallback_to_polling(
hass: HomeAssistant, async_autosetup_sonos, soco, caplog: pytest.LogCaptureFixture
hass: HomeAssistant,
config_entry,
soco,
fire_zgs_event,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that polling fallback works."""
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
# Do not wait on background tasks here because the
# subscription callback will fire an unsub the polling check
await hass.async_block_till_done()
await fire_zgs_event()
speaker = list(hass.data[DATA_SONOS].discovered.values())[0]
assert speaker.soco is soco
assert speaker._subscriptions
@ -30,7 +41,7 @@ async def test_fallback_to_polling(
),
):
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert not speaker._subscriptions
assert speaker.subscriptions_failed
@ -46,6 +57,7 @@ async def test_subscription_creation_fails(
side_effect=ConnectionError("Took too long"),
):
await async_setup_sonos()
await hass.async_block_till_done(wait_background_tasks=True)
speaker = list(hass.data[DATA_SONOS].discovered.values())[0]
assert not speaker._subscriptions

View File

@ -665,7 +665,7 @@ async def test_zone_attributes(
hass,
dt_util.utcnow() + timedelta(seconds=RELOAD_AFTER_UPDATE_DELAY + 1),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
entity_1_state = hass.states.get(DEVICE_1_ENTITY_ID)
assert entity_1_state.attributes[ATTR_SOUNDTOUCH_ZONE]["is_master"]

View File

@ -74,7 +74,7 @@ async def test_server_not_found(hass: HomeAssistant, mock_api: MagicMock) -> Non
hass,
dt_util.utcnow() + timedelta(minutes=61),
)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("sensor.speedtest_ping")
assert state is not None
assert state.state == STATE_UNAVAILABLE

View File

@ -97,7 +97,7 @@ async def test_sensor_process_fails(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
process_sensor = hass.states.get("binary_sensor.system_monitor_process_python3")
assert process_sensor is not None

View File

@ -232,7 +232,7 @@ async def test_sensor_updating(
mock_psutil.virtual_memory.side_effect = Exception("Failed to update")
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
memory_sensor = hass.states.get("sensor.system_monitor_memory_free")
assert memory_sensor is not None
@ -248,7 +248,7 @@ async def test_sensor_updating(
)
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
memory_sensor = hass.states.get("sensor.system_monitor_memory_free")
assert memory_sensor is not None
@ -293,7 +293,7 @@ async def test_sensor_process_fails(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
process_sensor = hass.states.get("sensor.system_monitor_process_python3")
assert process_sensor is not None
@ -330,7 +330,7 @@ async def test_sensor_network_sensors(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
network_out_sensor = hass.states.get("sensor.system_monitor_network_out_eth1")
packets_out_sensor = hass.states.get("sensor.system_monitor_packets_out_eth1")
@ -362,7 +362,7 @@ async def test_sensor_network_sensors(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
network_out_sensor = hass.states.get("sensor.system_monitor_network_out_eth1")
packets_out_sensor = hass.states.get("sensor.system_monitor_packets_out_eth1")
@ -470,7 +470,7 @@ async def test_exception_handling_disk_sensor(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "OS error for /" in caplog.text
@ -483,7 +483,7 @@ async def test_exception_handling_disk_sensor(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert "OS error for /" in caplog.text
@ -498,7 +498,7 @@ async def test_exception_handling_disk_sensor(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
disk_sensor = hass.states.get("sensor.system_monitor_disk_free")
assert disk_sensor is not None
@ -528,7 +528,7 @@ async def test_cpu_percentage_is_zero_returns_unknown(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
cpu_sensor = hass.states.get("sensor.system_monitor_processor_use")
assert cpu_sensor is not None
@ -538,7 +538,7 @@ async def test_cpu_percentage_is_zero_returns_unknown(
freezer.tick(timedelta(minutes=1))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
cpu_sensor = hass.states.get("sensor.system_monitor_processor_use")
assert cpu_sensor is not None
@ -573,7 +573,7 @@ async def test_remove_obsolete_entities(
)
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# Fake an entity which should be removed as not supported and disabled
entity_registry.async_get_or_create(

View File

@ -79,7 +79,7 @@ async def test_state(hass: HomeAssistant, mock_socket, now) -> None:
mock_socket.recv.return_value = b"on"
async_fire_time_changed(hass, now + timedelta(seconds=45))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(TEST_ENTITY)

View File

@ -29,7 +29,7 @@ async def test_temperature_readback(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
async_fire_time_changed(hass, utcnow + timedelta(seconds=70))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
temperature = hass.states.get("sensor.mydevicename")
assert temperature

View File

@ -548,30 +548,30 @@ async def test_other_update_failures(hass: HomeAssistant) -> None:
# then an error: ServiceUnavailable --> UpdateFailed
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
assert mock_request.call_count == 2
# works again
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL * 2)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 3
# then an error: TotalConnectError --> UpdateFailed
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL * 3)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
assert mock_request.call_count == 4
# works again
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL * 4)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_ALARM_DISARMED
assert mock_request.call_count == 5
# unknown TotalConnect status via ValueError
async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL * 5)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
assert mock_request.call_count == 6

View File

@ -278,7 +278,7 @@ async def test_setup_nvr_errors_during_indexing(
mock_remote.return_value.index.side_effect = None
async_fire_time_changed(hass, now + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
camera_states = hass.states.async_all("camera")
@ -313,7 +313,7 @@ async def test_setup_nvr_errors_during_initialization(
mock_remote.side_effect = None
async_fire_time_changed(hass, now + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
camera_states = hass.states.async_all("camera")
@ -362,7 +362,7 @@ async def test_motion_recording_mode_properties(
] = True
async_fire_time_changed(hass, now + timedelta(seconds=31))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("camera.front")
@ -375,7 +375,7 @@ async def test_motion_recording_mode_properties(
mock_remote.return_value.get_camera.return_value["recordingIndicator"] = "DISABLED"
async_fire_time_changed(hass, now + timedelta(seconds=61))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("camera.front")
@ -387,7 +387,7 @@ async def test_motion_recording_mode_properties(
)
async_fire_time_changed(hass, now + timedelta(seconds=91))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("camera.front")
@ -399,7 +399,7 @@ async def test_motion_recording_mode_properties(
)
async_fire_time_changed(hass, now + timedelta(seconds=121))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get("camera.front")

View File

@ -195,7 +195,7 @@ async def test_update(hass: HomeAssistant, freezer: FrozenDateTimeFactory) -> No
with patch.object(MockWs66i, "open") as method_call:
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert not method_call.called
@ -226,13 +226,13 @@ async def test_failed_update(
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# Failed update, close called
with patch.object(MockWs66i, "zone_status", return_value=None):
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.is_state(ZONE_1_ID, STATE_UNAVAILABLE)
@ -240,12 +240,12 @@ async def test_failed_update(
with patch.object(MockWs66i, "zone_status", return_value=None):
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# A connection re-attempt succeeds
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# confirm entity is back on
state = hass.states.get(ZONE_1_ID)
@ -315,7 +315,7 @@ async def test_source_select(
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
state = hass.states.get(ZONE_1_ID)
@ -370,14 +370,14 @@ async def test_volume_up_down(
)
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# should not go below zero
assert ws66i.zones[11].volume == 0
await _call_media_player_service(hass, SERVICE_VOLUME_UP, {"entity_id": ZONE_1_ID})
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert ws66i.zones[11].volume == 1
await _call_media_player_service(
@ -385,14 +385,14 @@ async def test_volume_up_down(
)
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert ws66i.zones[11].volume == MAX_VOL
await _call_media_player_service(hass, SERVICE_VOLUME_UP, {"entity_id": ZONE_1_ID})
freezer.tick(POLL_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
# should not go above 38 (MAX_VOL)
assert ws66i.zones[11].volume == MAX_VOL

View File

@ -238,7 +238,7 @@ async def test_xiaomi_exceptions(hass: HomeAssistant, mock_mirobo_is_on) -> None
mock_mirobo_is_on.status.side_effect = DeviceException("dummy exception")
future = dt_util.utcnow() + timedelta(seconds=60)
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert not is_available()
@ -247,7 +247,7 @@ async def test_xiaomi_exceptions(hass: HomeAssistant, mock_mirobo_is_on) -> None
mock_mirobo_is_on.status.reset_mock()
future += timedelta(seconds=60)
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
assert not is_available()
assert mock_mirobo_is_on.status.call_count == 1

View File

@ -76,7 +76,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.side_effect = ConnectionError("Could not connect")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=1))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_UNAVAILABLE
@ -84,7 +84,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.side_effect = ConnectionError("Could not connect")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=2))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_UNAVAILABLE
@ -92,7 +92,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.side_effect = TimeoutError("Could not connect")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=3))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_UNAVAILABLE
@ -100,7 +100,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.side_effect = UnknownError("info")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=4))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_UNAVAILABLE
@ -110,7 +110,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.return_value = load_json
client.get_armed_status.return_value = YALE_STATE_ARM_FULL
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_ALARM_ARMED_AWAY
@ -118,7 +118,7 @@ async def test_coordinator_setup_and_update_errors(
client.get_all.side_effect = AuthenticationError("Can not authenticate")
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=6))
await hass.async_block_till_done()
await hass.async_block_till_done(wait_background_tasks=True)
client.get_all.assert_called_once()
state = hass.states.get("alarm_control_panel.yale_smart_alarm")
assert state.state == STATE_UNAVAILABLE

View File

@ -588,6 +588,46 @@ async def test_async_get_hass_can_be_called(hass: HomeAssistant) -> None:
my_job_create_task.join()
async def test_async_add_executor_job_background(hass: HomeAssistant) -> None:
"""Test running an executor job in the background."""
calls = []
def job():
time.sleep(0.01)
calls.append(1)
async def _async_add_executor_job():
await hass.async_add_executor_job(job)
task = hass.async_create_background_task(
_async_add_executor_job(), "background", eager_start=True
)
await hass.async_block_till_done()
assert len(calls) == 0
await hass.async_block_till_done(wait_background_tasks=True)
assert len(calls) == 1
await task
async def test_async_add_executor_job(hass: HomeAssistant) -> None:
"""Test running an executor job."""
calls = []
def job():
time.sleep(0.01)
calls.append(1)
async def _async_add_executor_job():
await hass.async_add_executor_job(job)
task = hass.async_create_task(
_async_add_executor_job(), "background", eager_start=True
)
await hass.async_block_till_done()
assert len(calls) == 1
await task
async def test_stage_shutdown(hass: HomeAssistant) -> None:
"""Simulate a shutdown, test calling stuff."""
test_stop = async_capture_events(hass, EVENT_HOMEASSISTANT_STOP)