ha(H5): обёртка ошибок ESPHome-канала, README/RELEASE/ru-ниты
- ESPHome connect/command/импорт оборачиваются в AcceptanceError; при сбое connect канал закрывается (loop закрыт), CLI даёт rc 2 без traceback - self-test: connect error, command error, отсутствие aioesphomeapi через main (rc 2) — всего 15 acceptance-тестов - RELEASE_HA: repaired-wheel в dist/manylinux + удаление linux-тега перед upload; README компонента — корректная ссылка на docs/RELEASE_HA.md - translations/ru: options data «LAN-ключ»; план §2/§6 синхронизирован
This commit is contained in:
@@ -275,3 +275,91 @@ def test_esphome_channel_sends_mode_and_temperature(monkeypatch):
|
||||
assert instances[0].calls == [(7, "COOL", None), (7, None, 23.5)]
|
||||
assert instances[0].login is True
|
||||
assert instances[0].disconnected is True
|
||||
|
||||
|
||||
def _fake_module(client_cls, climate_info=None):
|
||||
fake = types.ModuleType("aioesphomeapi")
|
||||
fake.APIClient = client_cls
|
||||
fake.ClimateMode = SimpleNamespace(COOL="COOL", HEAT="HEAT")
|
||||
if climate_info is not None:
|
||||
fake.ClimateInfo = climate_info
|
||||
return fake
|
||||
|
||||
|
||||
def test_esphome_connect_error_is_acceptance_error(monkeypatch):
|
||||
class BadClient:
|
||||
def __init__(self, host, port, noise_psk=None):
|
||||
pass
|
||||
|
||||
async def connect(self, login=False):
|
||||
raise RuntimeError("connect boom")
|
||||
|
||||
async def disconnect(self):
|
||||
pass
|
||||
|
||||
monkeypatch.setitem(sys.modules, "aioesphomeapi",
|
||||
_fake_module(BadClient))
|
||||
channel = EsphomeChannel("bad.local", "")
|
||||
try:
|
||||
with pytest.raises(AcceptanceError, match="подключение"):
|
||||
channel.connect()
|
||||
finally:
|
||||
channel.close()
|
||||
assert channel._loop.is_closed()
|
||||
|
||||
|
||||
def test_main_esphome_connect_error_rc2(monkeypatch, capsys, mock_ha):
|
||||
class BadClient:
|
||||
def __init__(self, host, port, noise_psk=None):
|
||||
pass
|
||||
|
||||
async def connect(self, login=False):
|
||||
raise RuntimeError("connect boom")
|
||||
|
||||
_, url = mock_ha
|
||||
monkeypatch.setitem(sys.modules, "aioesphomeapi",
|
||||
_fake_module(BadClient))
|
||||
rc = main([*QUICK_ARGS, "--ha-url", url, "--esphome-host", "1.2.3.4"])
|
||||
assert rc == 2
|
||||
assert "подключение" in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_main_esphome_missing_dependency_rc2(monkeypatch, capsys, mock_ha):
|
||||
_, url = mock_ha
|
||||
monkeypatch.setitem(sys.modules, "aioesphomeapi", None)
|
||||
rc = main([*QUICK_ARGS, "--ha-url", url, "--esphome-host", "1.2.3.4"])
|
||||
assert rc == 2
|
||||
assert "aioesphomeapi" in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_esphome_command_error_is_acceptance_error(monkeypatch):
|
||||
class ClimateInfo:
|
||||
key = 3
|
||||
|
||||
class BadCommandClient:
|
||||
def __init__(self, host, port, noise_psk=None):
|
||||
pass
|
||||
|
||||
async def connect(self, login=False):
|
||||
pass
|
||||
|
||||
async def list_entities_services(self):
|
||||
return [ClimateInfo()], []
|
||||
|
||||
async def climate_command(self, **kwargs):
|
||||
raise RuntimeError("command boom")
|
||||
|
||||
async def disconnect(self):
|
||||
pass
|
||||
|
||||
monkeypatch.setitem(sys.modules, "aioesphomeapi",
|
||||
_fake_module(BadCommandClient, ClimateInfo))
|
||||
channel = EsphomeChannel("bad.local", "")
|
||||
try:
|
||||
channel.connect()
|
||||
step = Step("hvac_mode", "climate", "set_hvac_mode",
|
||||
{"hvac_mode": "cool"}, "state", "cool")
|
||||
with pytest.raises(AcceptanceError, match="команда"):
|
||||
channel.apply(step)
|
||||
finally:
|
||||
channel.close()
|
||||
|
||||
Reference in New Issue
Block a user