mirror of
https://github.com/home-assistant/core.git
synced 2025-08-30 01:42:21 +02:00
Add tests for hassfest triggers module
This commit is contained in:
181
tests/hassfest/test_triggers.py
Normal file
181
tests/hassfest/test_triggers.py
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
"""Tests for hassfest triggers."""
|
||||||
|
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.util.yaml.loader import parse_yaml
|
||||||
|
from script.hassfest import triggers
|
||||||
|
from script.hassfest.model import Config, Integration
|
||||||
|
|
||||||
|
TRIGGER_DESCPRITION_FILENAME = "triggers.yaml"
|
||||||
|
TRIGGER_ICONS_FILENAME = "icons.json"
|
||||||
|
TRIGGER_STRINGS_FILENAME = "strings.json"
|
||||||
|
|
||||||
|
TRIGGER_DESCRIPTIONS = {
|
||||||
|
"valid": {
|
||||||
|
TRIGGER_DESCPRITION_FILENAME: """
|
||||||
|
_:
|
||||||
|
fields:
|
||||||
|
event:
|
||||||
|
example: sunrise
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- sunrise
|
||||||
|
- sunset
|
||||||
|
offset:
|
||||||
|
selector:
|
||||||
|
time: null
|
||||||
|
""",
|
||||||
|
TRIGGER_ICONS_FILENAME: {"triggers": {"_": {"trigger": "mdi:flash"}}},
|
||||||
|
TRIGGER_STRINGS_FILENAME: {
|
||||||
|
"triggers": {
|
||||||
|
"_": {
|
||||||
|
"name": "MQTT",
|
||||||
|
"description": "When a specific message is received on a given MQTT topic.",
|
||||||
|
"description_configured": "When an MQTT message has been received",
|
||||||
|
"fields": {
|
||||||
|
"event": {"name": "Event", "description": "The event."},
|
||||||
|
"offset": {"name": "Offset", "description": "The offset."},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
},
|
||||||
|
"yaml_missing_colon": {
|
||||||
|
TRIGGER_DESCPRITION_FILENAME: """
|
||||||
|
test:
|
||||||
|
fields
|
||||||
|
entity:
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
""",
|
||||||
|
"errors": ["Invalid triggers.yaml"],
|
||||||
|
},
|
||||||
|
"invalid_triggers_schema": {
|
||||||
|
TRIGGER_DESCPRITION_FILENAME: """
|
||||||
|
invalid_trigger:
|
||||||
|
fields:
|
||||||
|
entity:
|
||||||
|
selector:
|
||||||
|
invalid_selector: null
|
||||||
|
""",
|
||||||
|
"errors": ["Unknown selector type invalid_selector"],
|
||||||
|
},
|
||||||
|
"missing_strings_and_icons": {
|
||||||
|
TRIGGER_DESCPRITION_FILENAME: """
|
||||||
|
sun:
|
||||||
|
fields:
|
||||||
|
event:
|
||||||
|
example: sunrise
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- sunrise
|
||||||
|
- sunset
|
||||||
|
translation_key: event
|
||||||
|
offset:
|
||||||
|
selector:
|
||||||
|
time: null
|
||||||
|
""",
|
||||||
|
TRIGGER_ICONS_FILENAME: {"triggers": {}},
|
||||||
|
TRIGGER_STRINGS_FILENAME: {
|
||||||
|
"triggers": {
|
||||||
|
"sun": {
|
||||||
|
"fields": {
|
||||||
|
"offset": {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"errors": [
|
||||||
|
"has no icon",
|
||||||
|
"has no name",
|
||||||
|
"has no description",
|
||||||
|
"field event with no name",
|
||||||
|
"field event with no description",
|
||||||
|
"field event with a selector with a translation key",
|
||||||
|
"field offset with no name",
|
||||||
|
"field offset with no description",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def config():
|
||||||
|
"""Fixture for hassfest Config."""
|
||||||
|
return Config(
|
||||||
|
root=Path(".").absolute(),
|
||||||
|
specific_integrations=None,
|
||||||
|
action="validate",
|
||||||
|
requirements=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_core_integration():
|
||||||
|
"""Mock Integration to be a core one."""
|
||||||
|
with patch.object(Integration, "core", return_value=True):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
def get_integration(domain: str, config: Config):
|
||||||
|
"""Fixture for hassfest integration model."""
|
||||||
|
return Integration(
|
||||||
|
Path(domain),
|
||||||
|
_config=config,
|
||||||
|
_manifest={
|
||||||
|
"domain": domain,
|
||||||
|
"name": domain,
|
||||||
|
"documentation": "https://example.com",
|
||||||
|
"codeowners": ["@awesome"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_core_integration")
|
||||||
|
def test_validate(config: Config) -> None:
|
||||||
|
"""Test validate version with no key."""
|
||||||
|
|
||||||
|
def _load_yaml(fname, secrets=None):
|
||||||
|
domain, yaml_file = fname.split("/")
|
||||||
|
assert yaml_file == TRIGGER_DESCPRITION_FILENAME
|
||||||
|
|
||||||
|
trigger_descriptions = TRIGGER_DESCRIPTIONS[domain][yaml_file]
|
||||||
|
with io.StringIO(trigger_descriptions) as file:
|
||||||
|
return parse_yaml(file)
|
||||||
|
|
||||||
|
def _patched_path_read_text(path: Path):
|
||||||
|
domain = path.parent.name
|
||||||
|
filename = path.name
|
||||||
|
|
||||||
|
return json.dumps(TRIGGER_DESCRIPTIONS[domain][filename])
|
||||||
|
|
||||||
|
integrations = {
|
||||||
|
domain: get_integration(domain, config) for domain in TRIGGER_DESCRIPTIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch("script.hassfest.triggers.grep_dir", return_value=True),
|
||||||
|
patch("pathlib.Path.is_file", return_value=True),
|
||||||
|
patch("pathlib.Path.read_text", _patched_path_read_text),
|
||||||
|
patch("annotatedyaml.loader.load_yaml", side_effect=_load_yaml),
|
||||||
|
):
|
||||||
|
triggers.validate(integrations, config)
|
||||||
|
|
||||||
|
assert not config.errors
|
||||||
|
|
||||||
|
for domain, description in TRIGGER_DESCRIPTIONS.items():
|
||||||
|
assert len(integrations[domain].errors) == len(description["errors"]), (
|
||||||
|
f"Domain '{domain}' has unexpected errors: {integrations[domain].errors}"
|
||||||
|
)
|
||||||
|
for error, expected_error in zip(
|
||||||
|
integrations[domain].errors, description["errors"], strict=True
|
||||||
|
):
|
||||||
|
assert expected_error in error.error
|
Reference in New Issue
Block a user