"""Test hardware utilities.""" from unittest.mock import AsyncMock, patch from universal_silabs_flasher.const import ApplicationType from homeassistant.components.hassio import AddonError, AddonInfo, AddonState from homeassistant.components.homeassistant_hardware.util import ( FirmwareGuess, get_zha_device_path, guess_firmware_type, ) from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry ZHA_CONFIG_ENTRY = MockConfigEntry( domain="zha", unique_id="some_unique_id", data={ "device": { "path": "socket://1.2.3.4:5678", "baudrate": 115200, "flow_control": None, }, "radio_type": "ezsp", }, version=4, ) def test_get_zha_device_path() -> None: """Test extracting the ZHA device path from its config entry.""" assert ( get_zha_device_path(ZHA_CONFIG_ENTRY) == ZHA_CONFIG_ENTRY.data["device"]["path"] ) def test_get_zha_device_path_ignored_discovery() -> None: """Test extracting the ZHA device path from an ignored ZHA discovery.""" config_entry = MockConfigEntry( domain="zha", unique_id="some_unique_id", data={}, version=4, ) assert get_zha_device_path(config_entry) is None async def test_guess_firmware_type_unknown(hass: HomeAssistant) -> None: """Test guessing the firmware type.""" assert (await guess_firmware_type(hass, "/dev/missing")) == FirmwareGuess( is_running=False, firmware_type=ApplicationType.EZSP, source="unknown" ) async def test_guess_firmware_type(hass: HomeAssistant) -> None: """Test guessing the firmware.""" path = ZHA_CONFIG_ENTRY.data["device"]["path"] ZHA_CONFIG_ENTRY.add_to_hass(hass) ZHA_CONFIG_ENTRY.mock_state(hass, ConfigEntryState.NOT_LOADED) assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=False, firmware_type=ApplicationType.EZSP, source="zha" ) # When ZHA is running, we indicate as such when guessing ZHA_CONFIG_ENTRY.mock_state(hass, ConfigEntryState.LOADED) assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.EZSP, source="zha" ) mock_otbr_addon_manager = AsyncMock() mock_multipan_addon_manager = AsyncMock() with ( patch( "homeassistant.components.homeassistant_hardware.util.is_hassio", return_value=True, ), patch( "homeassistant.components.homeassistant_hardware.util.get_otbr_addon_manager", return_value=mock_otbr_addon_manager, ), patch( "homeassistant.components.homeassistant_hardware.util.get_multiprotocol_addon_manager", return_value=mock_multipan_addon_manager, ), ): mock_otbr_addon_manager.async_get_addon_info.side_effect = AddonError() mock_multipan_addon_manager.async_get_addon_info.side_effect = AddonError() # Hassio errors are ignored and we still go with ZHA assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.EZSP, source="zha" ) mock_otbr_addon_manager.async_get_addon_info.side_effect = None mock_otbr_addon_manager.async_get_addon_info.return_value = AddonInfo( available=True, hostname=None, options={"device": "/some/other/device"}, state=AddonState.RUNNING, update_available=False, version="1.0.0", ) # We will prefer ZHA, as it is running (and actually pointing to the device) assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.EZSP, source="zha" ) mock_otbr_addon_manager.async_get_addon_info.return_value = AddonInfo( available=True, hostname=None, options={"device": path}, state=AddonState.NOT_RUNNING, update_available=False, version="1.0.0", ) # We will still prefer ZHA, as it is the one actually running assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.EZSP, source="zha" ) mock_otbr_addon_manager.async_get_addon_info.return_value = AddonInfo( available=True, hostname=None, options={"device": path}, state=AddonState.RUNNING, update_available=False, version="1.0.0", ) # Finally, ZHA loses out to OTBR assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.SPINEL, source="otbr" ) mock_multipan_addon_manager.async_get_addon_info.side_effect = None mock_multipan_addon_manager.async_get_addon_info.return_value = AddonInfo( available=True, hostname=None, options={"device": path}, state=AddonState.RUNNING, update_available=False, version="1.0.0", ) # Which will lose out to multi-PAN assert (await guess_firmware_type(hass, path)) == FirmwareGuess( is_running=True, firmware_type=ApplicationType.CPC, source="multiprotocol" )