Fix races in ESPHome manager tests (#110867)

This commit is contained in:
J. Nick Koston 2024-02-18 10:06:57 -06:00 committed by GitHub
parent addc02fa86
commit bd4f8e0cc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,4 +1,5 @@
"""Test ESPHome manager.""" """Test ESPHome manager."""
import asyncio
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from unittest.mock import AsyncMock, call from unittest.mock import AsyncMock, call
@ -354,7 +355,12 @@ async def test_unique_id_updated_to_mac(
unique_id="mock-config-name", unique_id="mock-config-name",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
subscribe_done = hass.loop.create_future()
async def async_subscribe_states(*args, **kwargs) -> None:
subscribe_done.set_result(None)
mock_client.subscribe_states = async_subscribe_states
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo( return_value=DeviceInfo(
mac_address="1122334455aa", mac_address="1122334455aa",
@ -363,6 +369,8 @@ async def test_unique_id_updated_to_mac(
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await subscribe_done
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
@ -382,13 +390,20 @@ async def test_unique_id_not_updated_if_name_same_and_already_mac(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
disconnect_done = hass.loop.create_future()
async def async_disconnect(*args, **kwargs) -> None:
disconnect_done.set_result(None)
mock_client.disconnect = async_disconnect
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455ab", name="test") return_value=DeviceInfo(mac_address="1122334455ab", name="test")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await disconnect_done
# Mac should never update # Mac should never update
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
@ -404,13 +419,20 @@ async def test_unique_id_updated_if_name_unset_and_already_mac(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
disconnect_done = hass.loop.create_future()
async def async_disconnect(*args, **kwargs) -> None:
disconnect_done.set_result(None)
mock_client.disconnect = async_disconnect
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455ab", name="test") return_value=DeviceInfo(mac_address="1122334455ab", name="test")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await disconnect_done
# Mac should never update # Mac should never update
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
@ -431,13 +453,20 @@ async def test_unique_id_not_updated_if_name_different_and_already_mac(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
disconnect_done = hass.loop.create_future()
async def async_disconnect(*args, **kwargs) -> None:
disconnect_done.set_result(None)
mock_client.disconnect = async_disconnect
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455ab", name="different") return_value=DeviceInfo(mac_address="1122334455ab", name="different")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await disconnect_done
# Mac should not be updated because name is different # Mac should not be updated because name is different
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
@ -460,13 +489,20 @@ async def test_name_updated_only_if_mac_matches(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
subscribe_done = hass.loop.create_future()
async def async_subscribe_states(*args, **kwargs) -> None:
subscribe_done.set_result(None)
mock_client.subscribe_states = async_subscribe_states
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455aa", name="new") return_value=DeviceInfo(mac_address="1122334455aa", name="new")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await subscribe_done
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
assert entry.data[CONF_DEVICE_NAME] == "new" assert entry.data[CONF_DEVICE_NAME] == "new"
@ -487,13 +523,20 @@ async def test_name_updated_only_if_mac_was_unset(
unique_id="notamac", unique_id="notamac",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
subscribe_done = hass.loop.create_future()
async def async_subscribe_states(*args, **kwargs) -> None:
subscribe_done.set_result(None)
mock_client.subscribe_states = async_subscribe_states
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455aa", name="new") return_value=DeviceInfo(mac_address="1122334455aa", name="new")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await subscribe_done
assert entry.unique_id == "11:22:33:44:55:aa" assert entry.unique_id == "11:22:33:44:55:aa"
assert entry.data[CONF_DEVICE_NAME] == "new" assert entry.data[CONF_DEVICE_NAME] == "new"
@ -517,13 +560,20 @@ async def test_connection_aborted_wrong_device(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
disconnect_done = hass.loop.create_future()
async def async_disconnect(*args, **kwargs) -> None:
disconnect_done.set_result(None)
mock_client.disconnect = async_disconnect
mock_client.device_info = AsyncMock( mock_client.device_info = AsyncMock(
return_value=DeviceInfo(mac_address="1122334455ab", name="different") return_value=DeviceInfo(mac_address="1122334455ab", name="different")
) )
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await disconnect_done
assert ( assert (
"Unexpected device found at 192.168.43.183; expected `test` " "Unexpected device found at 192.168.43.183; expected `test` "
@ -532,8 +582,7 @@ async def test_connection_aborted_wrong_device(
) )
assert "Error getting setting up connection for" not in caplog.text assert "Error getting setting up connection for" not in caplog.text
assert len(mock_client.disconnect.mock_calls) == 1 mock_client.disconnect = AsyncMock()
mock_client.disconnect.reset_mock()
caplog.clear() caplog.clear()
# Make sure discovery triggers a reconnect # Make sure discovery triggers a reconnect
service_info = dhcp.DhcpServiceInfo( service_info = dhcp.DhcpServiceInfo(
@ -575,15 +624,20 @@ async def test_failure_during_connect(
unique_id="11:22:33:44:55:aa", unique_id="11:22:33:44:55:aa",
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)
disconnect_done = hass.loop.create_future()
async def async_disconnect(*args, **kwargs) -> None:
disconnect_done.set_result(None)
mock_client.disconnect = async_disconnect
mock_client.device_info = AsyncMock(side_effect=APIConnectionError("fail")) mock_client.device_info = AsyncMock(side_effect=APIConnectionError("fail"))
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
async with asyncio.timeout(1):
await disconnect_done
assert "Error getting setting up connection for" in caplog.text assert "Error getting setting up connection for" in caplog.text
# Ensure we disconnect so that the reconnect logic is triggered
assert len(mock_client.disconnect.mock_calls) == 1
async def test_state_subscription( async def test_state_subscription(