[usb_host] Warn instead of failing when a device duplicates a usb_uart entry (#20373)

This commit is contained in:
J. Nick Koston
2026-10-09 16:38:05 -10:00
committed by GitHub
parent ba7d3bd770
commit dd45f8a6f8
2 changed files with 113 additions and 15 deletions
+74 -1
View File
@@ -1,9 +1,12 @@
"""Tests for usb_host device matching validation."""
import logging
import pytest
from esphome.components.usb_host import validate_usb_clients
from esphome.components.usb_host import _final_validate, validate_usb_clients
import esphome.config_validation as cv
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -109,3 +112,73 @@ def test_every_pair_is_compared_not_just_neighbours() -> None:
]
with pytest.raises(cv.Invalid, match="a, c"):
validate_usb_clients(configs)
def _run_final_validate(
devices: list[ConfigType], uarts: list[ConfigType]
) -> ConfigType:
config = {"id": "usb_host", "devices": devices}
token = fv.full_config.set({"usb_host": config, "usb_uart": uarts})
try:
return _final_validate(config)
finally:
fv.full_config.reset(token)
def test_device_duplicating_usb_uart_warns(caplog: pytest.LogCaptureFixture) -> None:
devices = [{"id": "device_0", "vid": 0x303A, "pid": 0x4001}]
uarts = [{"id": "uart_0", "vid": 0x303A, "pid": 0x4001}]
with caplog.at_level(logging.WARNING):
_run_final_validate(devices, uarts)
assert "'device_0'" in caplog.text
assert "'uart_0'" in caplog.text
assert "remove it from usb_host devices" in caplog.text
def test_wildcard_device_covering_usb_uart_suggests_narrowing(
caplog: pytest.LogCaptureFixture,
) -> None:
devices = [{"id": "device_0", "vid": 0x303A, "pid": 0}]
uarts = [{"id": "uart_0", "vid": 0x303A, "pid": 0x4001}]
with caplog.at_level(logging.WARNING):
_run_final_validate(devices, uarts)
assert "narrow its filter" in caplog.text
assert "remove it" not in caplog.text
def test_disjoint_device_and_usb_uart_do_not_warn(
caplog: pytest.LogCaptureFixture,
) -> None:
devices = [{"id": "device_0", "vid": 0x303A, "pid": 0x4002}]
uarts = [{"id": "uart_0", "vid": 0x303A, "pid": 0x4001}]
with caplog.at_level(logging.WARNING):
_run_final_validate(devices, uarts)
assert caplog.text == ""
_DUPLICATE_CLIENTS = [
{"id": "a", "vid": 0x303A, "pid": 0x4001},
{"id": "b", "vid": 0x303A, "pid": 0x4001},
]
@pytest.mark.parametrize(
("devices", "uarts"),
[([*_DUPLICATE_CLIENTS], []), ([], [*_DUPLICATE_CLIENTS])],
ids=["devices", "uarts"],
)
def test_overlap_within_one_component_is_rejected(
devices: list[ConfigType], uarts: list[ConfigType]
) -> None:
with pytest.raises(cv.Invalid, match="a, b"):
_run_final_validate(devices, uarts)
def test_device_inside_broader_usb_uart_suggests_removing(
caplog: pytest.LogCaptureFixture,
) -> None:
devices = [{"id": "device_0", "vid": 0x303A, "pid": 0x4001}]
uarts = [{"id": "uart_0", "vid": 0x303A, "pid": 0}]
with caplog.at_level(logging.WARNING):
_run_final_validate(devices, uarts)
assert "remove it from usb_host devices" in caplog.text