core/tests/helpers/test_check_config.py

267 lines
8.8 KiB
Python

"""Test check_config helper."""
import logging
from unittest.mock import Mock, patch
from homeassistant.config import YAML_CONFIG_FILE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.check_config import (
CheckConfigError,
async_check_ha_config_file,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.requirements import RequirementsNotFound
from tests.common import MockModule, mock_integration, mock_platform, patch_yaml_files
_LOGGER = logging.getLogger(__name__)
BASE_CONFIG = (
"homeassistant:\n"
" name: Home\n"
" latitude: -26.107361\n"
" longitude: 28.054500\n"
" elevation: 1600\n"
" unit_system: metric\n"
" time_zone: GMT\n"
"\n\n"
)
BAD_CORE_CONFIG = "homeassistant:\n unit_system: bad\n\n\n"
def log_ha_config(conf):
"""Log the returned config."""
cnt = 0
_LOGGER.debug("CONFIG - %s lines - %s errors", len(conf), len(conf.errors))
for key, val in conf.items():
_LOGGER.debug("#%s - %s: %s", cnt, key, val)
cnt += 1
for cnt, err in enumerate(conf.errors):
_LOGGER.debug("error[%s] = %s", cnt, err)
async def test_bad_core_config(hass: HomeAssistant) -> None:
"""Test a bad core config setup."""
files = {YAML_CONFIG_FILE: BAD_CORE_CONFIG}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert isinstance(res.errors[0].message, str)
assert res.errors[0].domain == "homeassistant"
assert res.errors[0].config == {"unit_system": "bad"}
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
async def test_config_platform_valid(hass: HomeAssistant) -> None:
"""Test a valid platform setup."""
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: demo"}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant", "light"}
assert res["light"] == [{"platform": "demo"}]
assert not res.errors
async def test_component_platform_not_found(hass: HomeAssistant) -> None:
"""Test errors if component or platform not found."""
# Make sure they don't exist
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant"}
assert res.errors[0] == CheckConfigError(
"Integration error: beer - Integration 'beer' not found.", None, None
)
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
async def test_component_requirement_not_found(hass: HomeAssistant) -> None:
"""Test errors if component with a requirement not found not found."""
# Make sure they don't exist
files = {YAML_CONFIG_FILE: BASE_CONFIG + "test_custom_component:"}
with patch(
"homeassistant.helpers.check_config.async_get_integration_with_requirements",
side_effect=RequirementsNotFound("test_custom_component", ["any"]),
), patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant"}
assert res.errors[0] == CheckConfigError(
(
"Integration error: test_custom_component - Requirements for"
" test_custom_component not found: ['any']."
),
None,
None,
)
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
async def test_component_not_found_safe_mode(hass: HomeAssistant) -> None:
"""Test no errors if component not found in safe mode."""
# Make sure they don't exist
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
hass.config.safe_mode = True
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant"}
assert not res.errors
async def test_component_platform_not_found_2(hass: HomeAssistant) -> None:
"""Test errors if component or platform not found."""
# Make sure they don't exist
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: beer"}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant", "light"}
assert res["light"] == []
assert res.errors[0] == CheckConfigError(
"Platform error light.beer - Integration 'beer' not found.", None, None
)
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
async def test_platform_not_found_safe_mode(hass: HomeAssistant) -> None:
"""Test no errors if platform not found in safe_mode."""
# Make sure they don't exist
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: beer"}
hass.config.safe_mode = True
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant", "light"}
assert res["light"] == []
assert not res.errors
async def test_package_invalid(hass: HomeAssistant) -> None:
"""Test a valid platform setup."""
files = {YAML_CONFIG_FILE: BASE_CONFIG + ' packages:\n p1:\n group: ["a"]'}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.errors[0].domain == "homeassistant.packages.p1.group"
assert res.errors[0].config == {"group": ["a"]}
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
assert res.keys() == {"homeassistant"}
async def test_bootstrap_error(hass: HomeAssistant) -> None:
"""Test a valid platform setup."""
files = {YAML_CONFIG_FILE: BASE_CONFIG + "automation: !include no.yaml"}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.errors[0].domain is None
# Only 1 error expected
res.errors.pop(0)
assert not res.errors
async def test_automation_config_platform(hass: HomeAssistant) -> None:
"""Test automation async config."""
files = {
YAML_CONFIG_FILE: BASE_CONFIG
+ """
automation:
use_blueprint:
path: test_event_service.yaml
input:
trigger_event: blueprint_event
service_to_call: test.automation
input_datetime:
""",
hass.config.path(
"blueprints/automation/test_event_service.yaml"
): """
blueprint:
name: "Call service based on event"
domain: automation
input:
trigger_event:
service_to_call:
trigger:
platform: event
event_type: !input trigger_event
action:
service: !input service_to_call
""",
}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
assert len(res.get("automation", [])) == 1
assert len(res.errors) == 0
assert "input_datetime" in res
async def test_config_platform_raise(hass: HomeAssistant) -> None:
"""Test bad config validation platform."""
mock_platform(
hass,
"bla.config",
Mock(async_validate_config=Mock(side_effect=Exception("Broken"))),
)
files = {
YAML_CONFIG_FILE: BASE_CONFIG
+ """
bla:
value: 1
""",
}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
assert len(res.errors) == 1
err = res.errors[0]
assert err.domain == "bla"
assert err.message == "Unexpected error calling config validator: Broken"
assert err.config == {"value": 1}
async def test_removed_yaml_support(hass: HomeAssistant) -> None:
"""Test config validation check with removed CONFIG_SCHEMA without raise if present."""
mock_integration(
hass,
MockModule(
domain="bla", config_schema=cv.removed("bla", raise_if_present=False)
),
False,
)
files = {YAML_CONFIG_FILE: BASE_CONFIG + "bla:\n platform: demo"}
with patch("os.path.isfile", return_value=True), patch_yaml_files(files):
res = await async_check_ha_config_file(hass)
log_ha_config(res)
assert res.keys() == {"homeassistant"}