Skip to content

Commit

Permalink
Catch unexpected exceptions when validating config (#31795)
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Feb 13, 2020
1 parent 6211a2b commit fbbb29a
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 1 deletion.
20 changes: 20 additions & 0 deletions homeassistant/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"):
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand Down
98 changes: 97 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
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
Expand Down Expand Up @@ -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
)

0 comments on commit fbbb29a

Please sign in to comment.