mirror of
https://github.com/esphome/esphome.git
synced 2026-10-11 13:54:12 +00:00
[sendspin] Add the static pairing code, pairing window and unpaired access option (#20348)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""Validation tests for the sendspin hub's pairing options.
|
||||
|
||||
These cover the rejection branches, which a compile test cannot reach: a
|
||||
`test*.yaml` can only assert that a configuration is accepted.
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config_validation as cv
|
||||
from esphome.components.sendspin import CONF_STATIC_PAIRING_CODE, CONFIG_SCHEMA
|
||||
from esphome.const import PlatformFramework
|
||||
from esphome.types import ConfigType
|
||||
from tests.component_tests.types import SetCoreConfigCallable
|
||||
|
||||
|
||||
def _hub_config(**overrides: Any) -> ConfigType:
|
||||
"""Build a minimal valid hub config, allowing field overrides."""
|
||||
config: ConfigType = {"id": "sendspin_hub_id"}
|
||||
config.update(overrides)
|
||||
return config
|
||||
|
||||
|
||||
def test_minimal_config_is_accepted(set_core_config: SetCoreConfigCallable) -> None:
|
||||
"""The baseline the rejection tests vary is itself valid."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
config = CONFIG_SCHEMA(_hub_config())
|
||||
|
||||
assert CONF_STATIC_PAIRING_CODE not in config
|
||||
|
||||
|
||||
@pytest.mark.parametrize("code", ["01234567", "00000000", "99999999"])
|
||||
def test_static_pairing_code_accepted(
|
||||
set_core_config: SetCoreConfigCallable, code: str
|
||||
) -> None:
|
||||
"""Eight decimal digits, leading zeros included, pass through unchanged."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
assert (
|
||||
CONFIG_SCHEMA(_hub_config(static_pairing_code=code))[CONF_STATIC_PAIRING_CODE]
|
||||
== code
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"code",
|
||||
[
|
||||
"0123456", # too short
|
||||
"012345678", # too long
|
||||
"0123456a", # not all decimal digits
|
||||
"0123 567", # whitespace is not a digit
|
||||
"01234567", # full-width digits are not ASCII
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_static_pairing_code_rejected(
|
||||
set_core_config: SetCoreConfigCallable, code: str
|
||||
) -> None:
|
||||
"""Anything that is not exactly eight decimal digits is refused here, since the
|
||||
library would otherwise refuse to start the client."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
with pytest.raises(cv.Invalid, match="exactly 8 decimal digits"):
|
||||
CONFIG_SCHEMA(_hub_config(static_pairing_code=code))
|
||||
|
||||
|
||||
def test_unquoted_static_pairing_code_rejected(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
) -> None:
|
||||
"""An unquoted YAML code arrives as an int, having already lost its leading
|
||||
zeros, so it is refused rather than silently pairing with the wrong value."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
with pytest.raises(cv.Invalid):
|
||||
CONFIG_SCHEMA(_hub_config(static_pairing_code=1234567))
|
||||
@@ -0,0 +1,75 @@
|
||||
"""Validation tests for the hub's unpaired access policy."""
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.sendspin import (
|
||||
CONF_UNPAIRED_ACCESS,
|
||||
CONFIG_SCHEMA as HUB_CONFIG_SCHEMA,
|
||||
FINAL_VALIDATE_SCHEMA as HUB_FINAL_VALIDATE_SCHEMA,
|
||||
)
|
||||
from esphome.const import PlatformFramework
|
||||
from tests.component_tests.types import SetCoreConfigCallable
|
||||
|
||||
HUB_ID = "sendspin_hub_id"
|
||||
NO_PAIRING_WARNING = "nothing lets a server pair"
|
||||
|
||||
|
||||
def test_hub_key_absent_by_default(set_core_config: SetCoreConfigCallable) -> None:
|
||||
"""Codegen leaves the hub's built-in default of on in place when the key is not set."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
assert CONF_UNPAIRED_ACCESS not in HUB_CONFIG_SCHEMA({"id": HUB_ID})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [True, False])
|
||||
def test_hub_key_accepted(set_core_config: SetCoreConfigCallable, value: bool) -> None:
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
|
||||
config = HUB_CONFIG_SCHEMA({"id": HUB_ID, CONF_UNPAIRED_ACCESS: value})
|
||||
|
||||
assert config[CONF_UNPAIRED_ACCESS] is value
|
||||
|
||||
|
||||
def test_off_without_pairing_method_warns(
|
||||
set_core_config: SetCoreConfigCallable, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""With unpaired access off and no way to pair, no server could ever play."""
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
config = HUB_CONFIG_SCHEMA({"id": HUB_ID, CONF_UNPAIRED_ACCESS: False})
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
HUB_FINAL_VALIDATE_SCHEMA(config)
|
||||
|
||||
assert NO_PAIRING_WARNING in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method", ["static_pairing_code"])
|
||||
def test_off_with_pairing_method_does_not_warn(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
method: str,
|
||||
) -> None:
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
hub_config = {"id": HUB_ID, CONF_UNPAIRED_ACCESS: False}
|
||||
if method == "static_pairing_code":
|
||||
hub_config["static_pairing_code"] = "01234567"
|
||||
config = HUB_CONFIG_SCHEMA(hub_config)
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
HUB_FINAL_VALIDATE_SCHEMA(config)
|
||||
|
||||
assert NO_PAIRING_WARNING not in caplog.text
|
||||
|
||||
|
||||
def test_on_does_not_warn(
|
||||
set_core_config: SetCoreConfigCallable, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
set_core_config(PlatformFramework.ESP32_IDF)
|
||||
config = HUB_CONFIG_SCHEMA({"id": HUB_ID})
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
HUB_FINAL_VALIDATE_SCHEMA(config)
|
||||
|
||||
assert NO_PAIRING_WARNING not in caplog.text
|
||||
Reference in New Issue
Block a user