WIP: Begin fixing unit tests

This commit is contained in:
puddly
2025-05-12 16:43:06 -04:00
parent 24bc6d3573
commit 2b35ad535f
3 changed files with 64 additions and 116 deletions

View File

@@ -19,7 +19,6 @@ from homeassistant.components.homeassistant_hardware.util import (
ApplicationType,
FirmwareInfo,
get_otbr_addon_manager,
get_zigbee_flasher_addon_manager,
)
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult, OptionsFlow
from homeassistant.core import HomeAssistant, callback
@@ -62,6 +61,18 @@ class FakeFirmwareConfigFlow(BaseFirmwareConfigFlow, domain=TEST_DOMAIN):
return await self.async_step_confirm()
async def async_step_install_zigbee_firmware(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Install Zigbee firmware."""
return await self.async_step_confirm_zigbee()
async def async_step_install_thread_firmware(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Install Thread firmware."""
return await self.async_step_start_otbr_addon()
def _async_flow_finished(self) -> ConfigFlowResult:
"""Create the config entry."""
assert self._device is not None
@@ -160,29 +171,8 @@ def mock_addon_info(
update_available=False,
version=None,
),
flasher_addon_info: AddonInfo = AddonInfo(
available=True,
hostname=None,
options={},
state=AddonState.NOT_INSTALLED,
update_available=False,
version=None,
),
) -> Iterator[tuple[Mock, Mock]]:
"""Mock the main addon states for the config flow."""
mock_flasher_manager = Mock(spec_set=get_zigbee_flasher_addon_manager(hass))
mock_flasher_manager.addon_name = "Silicon Labs Flasher"
mock_flasher_manager.async_start_addon_waiting = AsyncMock(
side_effect=delayed_side_effect()
)
mock_flasher_manager.async_install_addon_waiting = AsyncMock(
side_effect=delayed_side_effect()
)
mock_flasher_manager.async_uninstall_addon_waiting = AsyncMock(
side_effect=delayed_side_effect()
)
mock_flasher_manager.async_get_addon_info.return_value = flasher_addon_info
mock_otbr_manager = Mock(spec_set=get_otbr_addon_manager(hass))
mock_otbr_manager.addon_name = "OpenThread Border Router"
mock_otbr_manager.async_install_addon_waiting = AsyncMock(
@@ -216,10 +206,6 @@ def mock_addon_info(
"homeassistant.components.homeassistant_hardware.util.get_otbr_addon_manager",
return_value=mock_otbr_manager,
),
patch(
"homeassistant.components.homeassistant_hardware.firmware_config_flow.get_zigbee_flasher_addon_manager",
return_value=mock_flasher_manager,
),
patch(
"homeassistant.components.homeassistant_hardware.firmware_config_flow.is_hassio",
return_value=is_hassio,
@@ -233,7 +219,7 @@ def mock_addon_info(
return_value=firmware_info_result,
),
):
yield mock_otbr_manager, mock_flasher_manager
yield mock_otbr_manager
async def test_config_flow_zigbee(hass: HomeAssistant) -> None:
@@ -248,7 +234,7 @@ async def test_config_flow_zigbee(hass: HomeAssistant) -> None:
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option: we are now installing the addon
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -266,16 +252,6 @@ async def test_config_flow_zigbee(hass: HomeAssistant) -> None:
assert result["type"] is FlowResultType.SHOW_PROGRESS
assert result["step_id"] == "run_zigbee_flasher_addon"
assert result["progress_action"] == "run_zigbee_flasher_addon"
assert mock_flasher_manager.async_set_addon_options.mock_calls == [
call(
{
"device": TEST_DEVICE,
"baudrate": 115200,
"bootloader_baudrate": 115200,
"flow_control": True,
}
)
]
await hass.async_block_till_done(wait_background_tasks=True)
@@ -287,9 +263,6 @@ async def test_config_flow_zigbee(hass: HomeAssistant) -> None:
await hass.async_block_till_done(wait_background_tasks=True)
# We are finally done with the addon
assert mock_flasher_manager.async_uninstall_addon_waiting.mock_calls == [call()]
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "confirm_zigbee"
@@ -344,7 +317,7 @@ async def test_config_flow_zigbee_skip_step_if_installed(hass: HomeAssistant) ->
update_available=False,
version="1.2.3",
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option: we skip installation, instead we directly run it
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -419,7 +392,7 @@ async def test_config_flow_thread(hass: HomeAssistant) -> None:
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -507,7 +480,7 @@ async def test_config_flow_thread_addon_already_installed(hass: HomeAssistant) -
update_available=False,
version=None,
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -555,7 +528,7 @@ async def test_config_flow_zigbee_not_hassio(hass: HomeAssistant) -> None:
hass,
is_hassio=False,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={"next_step_id": STEP_PICK_FIRMWARE_ZIGBEE},
@@ -604,7 +577,7 @@ async def test_options_flow_zigbee_to_thread(hass: HomeAssistant) -> None:
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# First step is confirmation
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] is FlowResultType.MENU
@@ -703,7 +676,7 @@ async def test_options_flow_thread_to_zigbee(hass: HomeAssistant) -> None:
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option: we are now installing the addon
result = await hass.config_entries.options.async_configure(
result["flow_id"],

View File

@@ -54,7 +54,7 @@ async def test_config_flow_cannot_probe_firmware(
with mock_addon_info(
hass,
app_type=None,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Start the flow
result = await hass.config_entries.flow.async_init(
TEST_DOMAIN, context={"source": "hardware"}
@@ -85,7 +85,7 @@ async def test_config_flow_zigbee_not_hassio_wrong_firmware(
hass,
app_type=ApplicationType.SPINEL,
is_hassio=False,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -121,7 +121,7 @@ async def test_config_flow_zigbee_flasher_addon_already_running(
update_available=False,
version="1.0.0",
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -157,7 +157,7 @@ async def test_config_flow_zigbee_flasher_addon_info_fails(hass: HomeAssistant)
update_available=False,
version="1.0.0",
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_flasher_manager.async_get_addon_info.side_effect = AddonError()
result = await hass.config_entries.flow.async_configure(
@@ -188,7 +188,7 @@ async def test_config_flow_zigbee_flasher_addon_install_fails(
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_flasher_manager.async_install_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -222,7 +222,7 @@ async def test_config_flow_zigbee_flasher_addon_set_config_fails(
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_flasher_manager.async_install_addon_waiting = AsyncMock(
side_effect=delayed_side_effect()
)
@@ -258,7 +258,7 @@ async def test_config_flow_zigbee_flasher_run_fails(hass: HomeAssistant) -> None
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_flasher_manager.async_start_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -287,7 +287,7 @@ async def test_config_flow_zigbee_flasher_uninstall_fails(hass: HomeAssistant) -
with mock_addon_info(
hass,
app_type=ApplicationType.SPINEL,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_flasher_manager.async_uninstall_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -326,7 +326,7 @@ async def test_config_flow_zigbee_confirmation_fails(hass: HomeAssistant) -> Non
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
# Pick the menu option: we are now installing the addon
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@@ -338,7 +338,7 @@ async def test_config_flow_zigbee_confirmation_fails(hass: HomeAssistant) -> Non
with mock_addon_info(
hass,
app_type=None, # Probing fails
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -360,7 +360,7 @@ async def test_config_flow_thread_not_hassio(hass: HomeAssistant) -> None:
hass,
is_hassio=False,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -386,7 +386,7 @@ async def test_config_flow_thread_addon_info_fails(hass: HomeAssistant) -> None:
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_get_addon_info.side_effect = AddonError()
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
@@ -422,7 +422,7 @@ async def test_config_flow_thread_addon_already_running(hass: HomeAssistant) ->
update_available=False,
version="1.0.0",
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_install_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -453,7 +453,7 @@ async def test_config_flow_thread_addon_install_fails(hass: HomeAssistant) -> No
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_install_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -484,7 +484,7 @@ async def test_config_flow_thread_addon_set_config_fails(hass: HomeAssistant) ->
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_set_addon_options = AsyncMock(side_effect=AddonError())
result = await hass.config_entries.flow.async_configure(
@@ -515,7 +515,7 @@ async def test_config_flow_thread_flasher_run_fails(hass: HomeAssistant) -> None
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_start_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -543,7 +543,7 @@ async def test_config_flow_thread_flasher_uninstall_fails(hass: HomeAssistant) -
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
mock_otbr_manager.async_uninstall_addon_waiting = AsyncMock(
side_effect=AddonError()
)
@@ -580,7 +580,7 @@ async def test_config_flow_thread_confirmation_fails(hass: HomeAssistant) -> Non
with mock_addon_info(
hass,
app_type=ApplicationType.EZSP,
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -601,7 +601,7 @@ async def test_config_flow_thread_confirmation_fails(hass: HomeAssistant) -> Non
with mock_addon_info(
hass,
app_type=None, # Probing fails
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
@@ -694,7 +694,7 @@ async def test_options_flow_thread_to_zigbee_otbr_configured(
update_available=False,
version="1.0.0",
),
) as (mock_otbr_manager, mock_flasher_manager):
) as mock_otbr_manager:
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={"next_step_id": STEP_PICK_FIRMWARE_ZIGBEE},

View File

@@ -6,7 +6,7 @@ import asyncio
from collections.abc import AsyncGenerator
import dataclasses
import logging
from unittest.mock import AsyncMock, Mock, patch
from unittest.mock import Mock, patch
import aiohttp
from ha_silabs_firmware_client import FirmwareManifest, FirmwareMetadata
@@ -353,10 +353,14 @@ async def test_update_entity_installation(
"https://example.org/release_notes"
)
mock_firmware = Mock()
mock_flasher = AsyncMock()
async def mock_flash_firmware(fw_image, progress_callback):
async def mock_flash_firmware(
hass: HomeAssistant,
device: str,
fw_data: bytes,
expected_installed_firmware_type: ApplicationType,
bootloader_reset_type: str | None = None,
progress_callback: Callable[[int, int], None] | None = None,
) -> FirmwareInfo:
await asyncio.sleep(0)
progress_callback(0, 100)
await asyncio.sleep(0)
@@ -364,31 +368,20 @@ async def test_update_entity_installation(
await asyncio.sleep(0)
progress_callback(100, 100)
mock_flasher.flash_firmware = mock_flash_firmware
return FirmwareInfo(
device=TEST_DEVICE,
firmware_type=ApplicationType.EZSP,
firmware_version="7.4.4.0 build 0",
owners=[],
source="probe",
)
# When we install it, the other integration is reloaded
with (
patch(
"homeassistant.components.homeassistant_hardware.update.parse_firmware_image",
return_value=mock_firmware,
"homeassistant.components.homeassistant_hardware.update.async_flash_silabs_firmware",
side_effect=mock_flash_firmware,
),
patch(
"homeassistant.components.homeassistant_hardware.update.Flasher",
return_value=mock_flasher,
),
patch(
"homeassistant.components.homeassistant_hardware.update.probe_silabs_firmware_info",
return_value=FirmwareInfo(
device=TEST_DEVICE,
firmware_type=ApplicationType.EZSP,
firmware_version="7.4.4.0 build 0",
owners=[],
source="probe",
),
),
patch.object(
owning_config_entry, "async_unload", wraps=owning_config_entry.async_unload
) as owning_config_entry_unload,
):
state_changes: list[Event[EventStateChangedData]] = async_capture_events(
hass, EVENT_STATE_CHANGED
@@ -421,9 +414,6 @@ async def test_update_entity_installation(
assert state_changes[6].data["new_state"].attributes["update_percentage"] is None
assert state_changes[6].data["new_state"].attributes["in_progress"] is False
# The owning integration was unloaded and is again running
assert len(owning_config_entry_unload.mock_calls) == 1
# After the firmware update, the entity has the new version and the correct state
state_after_install = hass.states.get(TEST_UPDATE_ENTITY_ID)
assert state_after_install is not None
@@ -454,19 +444,10 @@ async def test_update_entity_installation_failure(
assert state_before_install.attributes["installed_version"] == "7.3.1.0"
assert state_before_install.attributes["latest_version"] == "7.4.4.0"
mock_flasher = AsyncMock()
mock_flasher.flash_firmware.side_effect = RuntimeError(
"Something broke during flashing!"
)
with (
patch(
"homeassistant.components.homeassistant_hardware.update.parse_firmware_image",
return_value=Mock(),
),
patch(
"homeassistant.components.homeassistant_hardware.update.Flasher",
return_value=mock_flasher,
"homeassistant.components.homeassistant_hardware.update.async_flash_silabs_firmware",
side_effect=HomeAssistantError("Failed to flash firmware"),
),
pytest.raises(HomeAssistantError, match="Failed to flash firmware"),
):
@@ -509,16 +490,10 @@ async def test_update_entity_installation_probe_failure(
with (
patch(
"homeassistant.components.homeassistant_hardware.update.parse_firmware_image",
return_value=Mock(),
),
patch(
"homeassistant.components.homeassistant_hardware.update.Flasher",
return_value=AsyncMock(),
),
patch(
"homeassistant.components.homeassistant_hardware.update.probe_silabs_firmware_info",
return_value=None,
"homeassistant.components.homeassistant_hardware.update.async_flash_silabs_firmware",
side_effect=HomeAssistantError(
"Failed to probe the firmware after flashing"
),
),
pytest.raises(
HomeAssistantError, match="Failed to probe the firmware after flashing"