ha(H2): ниты повторного ревью — pump без параллельных читателей, pending-рефкаунт, точная ошибка свойств

- session.py: новый лог-памп не поднимается, пока предыдущий не завершился
  (stopping/is_alive), параллельное чтение кольца исключено
- __init__: счётчик pending закрывает окно гонки setup/unload последней
  записи; warning при не-словарном fglair: в YAML
- trial: properties_missing — отдельная ошибка формы/abort (en/ru/strings)
- ConfigEntryNotReady: «порт 0» больше не показывается
- тесты: контраст одинакового явного порта, неблокирующий unload (тикер loop)
- план H5: публикация pyfglair именно на PyPI (manylinux x86_64/aarch64)
This commit is contained in:
2026-09-29 12:29:35 +03:00
parent da01c607a6
commit 29f62b639c
9 changed files with 109 additions and 26 deletions
+50
View File
@@ -1,6 +1,7 @@
"""Setup/unload ConfigEntry: клиент стартует, останавливается, ошибки порта."""
from __future__ import annotations
import asyncio
import socket
from helpers import free_port
@@ -50,6 +51,55 @@ async def test_two_entries_default_port(hass: HomeAssistant, entry_data, socket_
assert await hass.config_entries.async_unload(second.entry_id)
async def test_two_entries_same_explicit_port(
hass: HomeAssistant, entry_data, socket_enabled
):
"""Явно заданный один порт на две записи — вторая SETUP_RETRY."""
port = free_port()
first = MockConfigEntry(
domain=DOMAIN,
data={**entry_data, CONF_LISTEN_PORT: port},
unique_id="DSN-1",
)
first.add_to_hass(hass)
assert await hass.config_entries.async_setup(first.entry_id)
await hass.async_block_till_done()
second = MockConfigEntry(
domain=DOMAIN,
data={**entry_data, "dsn": "DSN-2", CONF_LISTEN_PORT: port},
unique_id="DSN-2",
)
second.add_to_hass(hass)
assert not await hass.config_entries.async_setup(second.entry_id)
await hass.async_block_till_done()
assert second.state.name == "SETUP_RETRY"
assert await hass.config_entries.async_unload(first.entry_id)
async def test_unload_does_not_block_loop(
hass: HomeAssistant, config_entry, socket_enabled
):
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
ticks = 0
async def ticker() -> None:
nonlocal ticks
while True:
await asyncio.sleep(0.01)
ticks += 1
task = asyncio.create_task(ticker())
await asyncio.sleep(0.05)
assert await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()
task.cancel()
assert ticks >= 3
async def test_setup_port_busy(hass: HomeAssistant, entry_data, socket_enabled):
port = free_port()
sock = socket.socket()