mirror of https://github.com/home-assistant/core
278 lines
9.8 KiB
Python
278 lines
9.8 KiB
Python
"""Tests for the reload helper."""
|
|
|
|
import logging
|
|
from unittest.mock import AsyncMock, Mock, patch
|
|
|
|
import pytest
|
|
import voluptuous as vol
|
|
|
|
from homeassistant import config
|
|
from homeassistant.const import SERVICE_RELOAD
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ConfigValidationError, HomeAssistantError
|
|
from homeassistant.helpers.entity_component import EntityComponent
|
|
from homeassistant.helpers.entity_platform import async_get_platforms
|
|
from homeassistant.helpers.reload import (
|
|
async_get_platform_without_config_entry,
|
|
async_integration_yaml_config,
|
|
async_reload_integration_platforms,
|
|
async_setup_reload_service,
|
|
)
|
|
from homeassistant.loader import async_get_integration
|
|
|
|
from tests.common import (
|
|
MockModule,
|
|
MockPlatform,
|
|
get_fixture_path,
|
|
mock_integration,
|
|
mock_platform,
|
|
)
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
DOMAIN = "test_domain"
|
|
PLATFORM = "test_platform"
|
|
|
|
|
|
async def test_reload_platform(hass: HomeAssistant) -> None:
|
|
"""Test the polling of only updated entities."""
|
|
component_setup = Mock(return_value=True)
|
|
|
|
setup_called = []
|
|
|
|
async def setup_platform(*args):
|
|
setup_called.append(args)
|
|
|
|
mock_integration(hass, MockModule(DOMAIN, setup=component_setup))
|
|
mock_integration(hass, MockModule(PLATFORM, dependencies=[DOMAIN]))
|
|
|
|
platform = MockPlatform(async_setup_platform=setup_platform)
|
|
mock_platform(hass, f"{PLATFORM}.{DOMAIN}", platform)
|
|
|
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
|
|
|
await component.async_setup({DOMAIN: {"platform": PLATFORM, "sensors": None}})
|
|
await hass.async_block_till_done()
|
|
assert component_setup.called
|
|
|
|
assert f"{PLATFORM}.{DOMAIN}" in hass.config.components
|
|
assert len(setup_called) == 1
|
|
|
|
platform = async_get_platform_without_config_entry(hass, PLATFORM, DOMAIN)
|
|
assert platform.platform_name == PLATFORM
|
|
assert platform.domain == DOMAIN
|
|
|
|
yaml_path = get_fixture_path("helpers/reload_configuration.yaml")
|
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
|
await async_reload_integration_platforms(hass, PLATFORM, [DOMAIN])
|
|
|
|
assert len(setup_called) == 2
|
|
|
|
existing_platforms = async_get_platforms(hass, PLATFORM)
|
|
for existing_platform in existing_platforms:
|
|
existing_platform.config_entry = "abc"
|
|
assert not async_get_platform_without_config_entry(hass, PLATFORM, DOMAIN)
|
|
|
|
|
|
async def test_setup_reload_service(hass: HomeAssistant) -> None:
|
|
"""Test setting up a reload service."""
|
|
component_setup = Mock(return_value=True)
|
|
|
|
setup_called = []
|
|
|
|
async def setup_platform(*args):
|
|
setup_called.append(args)
|
|
|
|
mock_integration(hass, MockModule(DOMAIN, setup=component_setup))
|
|
mock_integration(hass, MockModule(PLATFORM, dependencies=[DOMAIN]))
|
|
|
|
platform = MockPlatform(async_setup_platform=setup_platform)
|
|
mock_platform(hass, f"{PLATFORM}.{DOMAIN}", platform)
|
|
|
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
|
|
|
await component.async_setup({DOMAIN: {"platform": PLATFORM, "sensors": None}})
|
|
await hass.async_block_till_done()
|
|
assert component_setup.called
|
|
|
|
assert f"{PLATFORM}.{DOMAIN}" in hass.config.components
|
|
assert len(setup_called) == 1
|
|
|
|
await async_setup_reload_service(hass, PLATFORM, [DOMAIN])
|
|
|
|
yaml_path = get_fixture_path("helpers/reload_configuration.yaml")
|
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
|
await hass.services.async_call(
|
|
PLATFORM,
|
|
SERVICE_RELOAD,
|
|
{},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(setup_called) == 2
|
|
|
|
|
|
async def test_setup_reload_service_when_async_process_component_config_fails(
|
|
hass: HomeAssistant,
|
|
) -> None:
|
|
"""Test setting up a reload service with the config processing failing."""
|
|
component_setup = Mock(return_value=True)
|
|
|
|
setup_called = []
|
|
|
|
async def setup_platform(*args):
|
|
setup_called.append(args)
|
|
|
|
mock_integration(hass, MockModule(DOMAIN, setup=component_setup))
|
|
mock_integration(hass, MockModule(PLATFORM, dependencies=[DOMAIN]))
|
|
|
|
platform = MockPlatform(async_setup_platform=setup_platform)
|
|
mock_platform(hass, f"{PLATFORM}.{DOMAIN}", platform)
|
|
|
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
|
|
|
await component.async_setup({DOMAIN: {"platform": PLATFORM, "sensors": None}})
|
|
await hass.async_block_till_done()
|
|
assert component_setup.called
|
|
|
|
assert f"{PLATFORM}.{DOMAIN}" in hass.config.components
|
|
assert len(setup_called) == 1
|
|
|
|
await async_setup_reload_service(hass, PLATFORM, [DOMAIN])
|
|
|
|
yaml_path = get_fixture_path("helpers/reload_configuration.yaml")
|
|
with (
|
|
patch.object(config, "YAML_CONFIG_FILE", yaml_path),
|
|
patch.object(
|
|
config,
|
|
"async_process_component_config",
|
|
return_value=config.IntegrationConfigInfo(None, []),
|
|
),
|
|
):
|
|
await hass.services.async_call(
|
|
PLATFORM,
|
|
SERVICE_RELOAD,
|
|
{},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(setup_called) == 1
|
|
|
|
|
|
async def test_setup_reload_service_with_platform_that_provides_async_reset_platform(
|
|
hass: HomeAssistant,
|
|
) -> None:
|
|
"""Test setting up a reload service using a platform that has its own async_reset_platform."""
|
|
component_setup = AsyncMock(return_value=True)
|
|
|
|
setup_called = []
|
|
async_reset_platform_called = []
|
|
|
|
async def setup_platform(*args):
|
|
setup_called.append(args)
|
|
|
|
async def async_reset_platform(*args):
|
|
async_reset_platform_called.append(args)
|
|
|
|
mock_integration(hass, MockModule(DOMAIN, async_setup=component_setup))
|
|
integration = await async_get_integration(hass, DOMAIN)
|
|
integration.get_component().async_reset_platform = async_reset_platform
|
|
|
|
mock_integration(hass, MockModule(PLATFORM, dependencies=[DOMAIN]))
|
|
|
|
platform = MockPlatform(async_setup_platform=setup_platform)
|
|
mock_platform(hass, f"{PLATFORM}.{DOMAIN}", platform)
|
|
|
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
|
|
|
await component.async_setup({DOMAIN: {"platform": PLATFORM, "name": "xyz"}})
|
|
await hass.async_block_till_done()
|
|
assert component_setup.called
|
|
|
|
assert f"{PLATFORM}.{DOMAIN}" in hass.config.components
|
|
assert len(setup_called) == 1
|
|
|
|
await async_setup_reload_service(hass, PLATFORM, [DOMAIN])
|
|
|
|
yaml_path = get_fixture_path("helpers/reload_configuration.yaml")
|
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
|
await hass.services.async_call(
|
|
PLATFORM,
|
|
SERVICE_RELOAD,
|
|
{},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(setup_called) == 1
|
|
assert len(async_reset_platform_called) == 1
|
|
|
|
|
|
async def test_async_integration_yaml_config(hass: HomeAssistant) -> None:
|
|
"""Test loading yaml config for an integration."""
|
|
mock_integration(hass, MockModule(DOMAIN))
|
|
|
|
yaml_path = get_fixture_path(f"helpers/{DOMAIN}_configuration.yaml")
|
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
|
processed_config = await async_integration_yaml_config(hass, DOMAIN)
|
|
assert processed_config == {DOMAIN: [{"name": "one"}, {"name": "two"}]}
|
|
# Test fetching yaml config does not raise when the raise_on_failure option is set
|
|
processed_config = await async_integration_yaml_config(
|
|
hass, DOMAIN, raise_on_failure=True
|
|
)
|
|
assert processed_config == {DOMAIN: [{"name": "one"}, {"name": "two"}]}
|
|
|
|
|
|
async def test_async_integration_failing_yaml_config(hass: HomeAssistant) -> None:
|
|
"""Test reloading yaml config for an integration fails.
|
|
|
|
In case an integration reloads its yaml configuration it should throw when
|
|
the new config failed to load and raise_on_failure is set to True.
|
|
"""
|
|
schema_without_name_attr = vol.Schema({vol.Required("some_option"): str})
|
|
|
|
mock_integration(hass, MockModule(DOMAIN, config_schema=schema_without_name_attr))
|
|
|
|
yaml_path = get_fixture_path(f"helpers/{DOMAIN}_configuration.yaml")
|
|
with patch.object(config, "YAML_CONFIG_FILE", yaml_path):
|
|
# Test fetching yaml config does not raise without raise_on_failure option
|
|
processed_config = await async_integration_yaml_config(hass, DOMAIN)
|
|
assert processed_config is None
|
|
# Test fetching yaml config does not raise when the raise_on_failure option is set
|
|
with pytest.raises(ConfigValidationError):
|
|
await async_integration_yaml_config(hass, DOMAIN, raise_on_failure=True)
|
|
|
|
|
|
async def test_async_integration_failing_on_reload(hass: HomeAssistant) -> None:
|
|
"""Test reloading yaml config for an integration fails with an other exception.
|
|
|
|
In case an integration reloads its yaml configuration it should throw when
|
|
the new config failed to load and raise_on_failure is set to True.
|
|
"""
|
|
mock_integration(hass, MockModule(DOMAIN))
|
|
|
|
yaml_path = get_fixture_path(f"helpers/{DOMAIN}_configuration.yaml")
|
|
with (
|
|
patch.object(config, "YAML_CONFIG_FILE", yaml_path),
|
|
patch(
|
|
"homeassistant.config.async_process_component_config",
|
|
side_effect=HomeAssistantError(),
|
|
),
|
|
pytest.raises(HomeAssistantError),
|
|
):
|
|
# Test fetching yaml config does raise when the raise_on_failure option is set
|
|
await async_integration_yaml_config(hass, DOMAIN, raise_on_failure=True)
|
|
|
|
|
|
async def test_async_integration_missing_yaml_config(hass: HomeAssistant) -> None:
|
|
"""Test loading missing yaml config for an integration."""
|
|
mock_integration(hass, MockModule(DOMAIN))
|
|
|
|
yaml_path = get_fixture_path("helpers/does_not_exist_configuration.yaml")
|
|
with (
|
|
pytest.raises(FileNotFoundError),
|
|
patch.object(config, "YAML_CONFIG_FILE", yaml_path),
|
|
):
|
|
await async_integration_yaml_config(hass, DOMAIN)
|