"""Repair issue при несовпадении LAN-ключа и его fix-flow.""" from __future__ import annotations import asyncio import time from helpers import DSN, KEY_ID from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir from homeassistant.setup import async_setup_component from test_entities import _setup_entry from custom_components.fglair.const import DOMAIN from pyfglair import State async def _wait_for(predicate, timeout: float = 20.0): deadline = time.monotonic() + timeout while time.monotonic() < deadline: result = predicate() if result: return result await asyncio.sleep(0.1) raise AssertionError("условие не выполнено за отведённое время") async def test_key_error_creates_and_fixes_issue( hass: HomeAssistant, mock_ac, socket_enabled ): assert await async_setup_component(hass, "repairs", {}) proc = mock_ac([], key_id=KEY_ID + 1) entry = await _setup_entry(hass, proc.port) runtime = entry.runtime_data await _wait_for(lambda: runtime.client.state == State.KEY_ERROR) registry = ir.async_get(hass) issue_id = f"key_mismatch_{DSN}" issue = registry.async_get_issue(DOMAIN, issue_id) assert issue is not None assert issue.is_fixable assert issue.translation_key == "key_mismatch" assert issue.translation_placeholders["device"] == "Mock AC" flow_manager = hass.data["repairs"]["flow_manager"] result = await flow_manager.async_init(DOMAIN, data={"issue_id": issue_id}) assert result["type"] == "form" result = await flow_manager.async_configure(result["flow_id"], {}) assert result["type"] == "create_entry" assert registry.async_get_issue(DOMAIN, issue_id) is None await hass.config_entries.async_unload(entry.entry_id) async def test_reconfigure_fixes_key_error( hass: HomeAssistant, mock_ac, socket_enabled ): """Repair-путь целиком: bad key_id → issue → reconfigure → online → issue снят.""" from homeassistant.config_entries import SOURCE_RECONFIGURE from test_config_flow import MANUAL_INPUT, PREVIEW_INPUT proc = mock_ac( ["--set", "operation_mode=6"], key_id=KEY_ID + 1 ) entry = await _setup_entry(hass, proc.port) runtime = entry.runtime_data await _wait_for(lambda: runtime.client.state == State.KEY_ERROR) registry = ir.async_get(hass) issue_id = f"key_mismatch_{DSN}" assert registry.async_get_issue(DOMAIN, issue_id) is not None # Mock помнит только один app_addr; останавливаем «залипшую» сессию, # чтобы пробная сессия config flow получила KE (штатно это делает reload). await runtime.client.async_stop() result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_RECONFIGURE, "entry_id": entry.entry_id}, ) result = await hass.config_entries.flow.async_configure( result["flow_id"], {"next_step_id": "manual"} ) result = await hass.config_entries.flow.async_configure( result["flow_id"], { **MANUAL_INPUT, "host": "127.0.0.1", "device_port": proc.port, "lanip_key_id": KEY_ID + 1, }, ) assert result["step_id"] == "preview", result.get("errors") result = await hass.config_entries.flow.async_configure( result["flow_id"], PREVIEW_INPUT ) assert result["type"] == "abort" assert result["reason"] == "reconfigure_successful" await hass.async_block_till_done() runtime = entry.runtime_data await _wait_for(lambda: runtime.client.state == State.ONLINE) assert registry.async_get_issue(DOMAIN, issue_id) is None assert entry.data["lanip_key_id"] == KEY_ID + 1 assert await hass.config_entries.async_unload(entry.entry_id)