Catch unexpected exceptions when validating config (#31795)

This commit is contained in:
Paulus Schoutsen 2020-02-13 13:43:07 -08:00 committed by GitHub
parent 6211a2bb98
commit fbbb29a6ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 1 deletions

View File

@ -697,6 +697,9 @@ async def async_process_component_config(
except (vol.Invalid, HomeAssistantError) as ex:
async_log_exception(ex, domain, config, hass, integration.documentation)
return None
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error calling %s config validator", domain)
return None
# No custom config validator, proceed with schema validation
if hasattr(component, "CONFIG_SCHEMA"):
@ -705,6 +708,9 @@ async def async_process_component_config(
except vol.Invalid as ex:
async_log_exception(ex, domain, config, hass, integration.documentation)
return None
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error calling %s CONFIG_SCHEMA", domain)
return None
component_platform_schema = getattr(
component, "PLATFORM_SCHEMA_BASE", getattr(component, "PLATFORM_SCHEMA", None)
@ -721,6 +727,13 @@ async def async_process_component_config(
except vol.Invalid as ex:
async_log_exception(ex, domain, p_config, hass, integration.documentation)
continue
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unknown error validating %s platform config with %s component platform schema",
p_name,
domain,
)
continue
# Not all platform components follow same pattern for platforms
# So if p_name is None we are not going to validate platform
@ -756,6 +769,13 @@ async def async_process_component_config(
p_integration.documentation,
)
continue
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unknown error validating config for %s platform for %s component with PLATFORM_SCHEMA",
p_name,
domain,
)
continue
platforms.append(p_validated)

View File

@ -4,9 +4,11 @@ import asyncio
from collections import OrderedDict
import copy
import os
import unittest.mock as mock
from unittest import mock
from unittest.mock import Mock
import asynctest
from asynctest import CoroutineMock, patch
import pytest
from voluptuous import Invalid, MultipleInvalid
import yaml
@ -893,3 +895,97 @@ async def test_merge_split_component_definition(hass):
assert len(config["light one"]) == 1
assert len(config["light two"]) == 1
assert len(config["light three"]) == 1
async def test_component_config_exceptions(hass, caplog):
"""Test unexpected exceptions validating component config."""
# Config validator
assert (
await config_util.async_process_component_config(
hass,
{},
integration=Mock(
domain="test_domain",
get_platform=Mock(
return_value=Mock(
async_validate_config=CoroutineMock(
side_effect=ValueError("broken")
)
)
),
),
)
is None
)
assert "ValueError: broken" in caplog.text
assert "Unknown error calling test_domain config validator" in caplog.text
# component.CONFIG_SCHEMA
caplog.clear()
assert (
await config_util.async_process_component_config(
hass,
{},
integration=Mock(
domain="test_domain",
get_platform=Mock(return_value=None),
get_component=Mock(
return_value=Mock(
CONFIG_SCHEMA=Mock(side_effect=ValueError("broken"))
)
),
),
)
is None
)
assert "ValueError: broken" in caplog.text
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
# component.PLATFORM_SCHEMA
caplog.clear()
assert await config_util.async_process_component_config(
hass,
{"test_domain": {"platform": "test_platform"}},
integration=Mock(
domain="test_domain",
get_platform=Mock(return_value=None),
get_component=Mock(
return_value=Mock(
spec=["PLATFORM_SCHEMA_BASE"],
PLATFORM_SCHEMA_BASE=Mock(side_effect=ValueError("broken")),
)
),
),
) == {"test_domain": []}
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating test_platform platform config with test_domain component platform schema"
in caplog.text
)
# platform.PLATFORM_SCHEMA
caplog.clear()
with patch(
"homeassistant.config.async_get_integration_with_requirements",
return_value=Mock( # integration that owns platform
get_platform=Mock(
return_value=Mock( # platform
PLATFORM_SCHEMA=Mock(side_effect=ValueError("broken"))
)
)
),
):
assert await config_util.async_process_component_config(
hass,
{"test_domain": {"platform": "test_platform"}},
integration=Mock(
domain="test_domain",
get_platform=Mock(return_value=None),
get_component=Mock(return_value=Mock(spec=["PLATFORM_SCHEMA_BASE"])),
),
) == {"test_domain": []}
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform platform for test_domain component with PLATFORM_SCHEMA"
in caplog.text
)