mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Allow parameterizing YAML config in tests (#87981)
* Add fixture to parameterize yaml config * Apply to more tests * Re-add @fixture label * Add fixtures to patch yaml content and targets * Typo * Improve docstr Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Update references to mock_yaml_configuration * Apply new fixtures * Apply to check_config tests * Follow up comments * Rename fixtures, update docstr * Split paths * Patch load_yaml_config_file instead * sort * Fix tests * improve docst * Rename fixtures * sorting Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Improve docstr Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Improve docstr Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Improve docstr Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Improve docstr Co-authored-by: Erik Montnemery <erik@montnemery.com> * Improve docstr Co-authored-by: Erik Montnemery <erik@montnemery.com> * Improve docstr Co-authored-by: Erik Montnemery <erik@montnemery.com> --------- Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
1759f58fc1
commit
4f6a25b470
@ -109,6 +109,9 @@ _TEST_FIXTURES: dict[str, list[str] | str] = {
|
|||||||
"hass_admin_user": "MockUser",
|
"hass_admin_user": "MockUser",
|
||||||
"hass_client": "ClientSessionGenerator",
|
"hass_client": "ClientSessionGenerator",
|
||||||
"hass_client_no_auth": "ClientSessionGenerator",
|
"hass_client_no_auth": "ClientSessionGenerator",
|
||||||
|
"hass_config": "ConfigType | None",
|
||||||
|
"hass_config_yaml": "str | None",
|
||||||
|
"hass_config_yaml_files": "dict[str, str] | None",
|
||||||
"hass_owner_user": "MockUser",
|
"hass_owner_user": "MockUser",
|
||||||
"hass_read_only_access_token": "str",
|
"hass_read_only_access_token": "str",
|
||||||
"hass_read_only_user": "MockUser",
|
"hass_read_only_user": "MockUser",
|
||||||
@ -126,6 +129,8 @@ _TEST_FIXTURES: dict[str, list[str] | str] = {
|
|||||||
"mock_bluetooth_adapters": "None",
|
"mock_bluetooth_adapters": "None",
|
||||||
"mock_device_tracker_conf": "list[Device]",
|
"mock_device_tracker_conf": "list[Device]",
|
||||||
"mock_get_source_ip": "None",
|
"mock_get_source_ip": "None",
|
||||||
|
"mock_hass_config": "None",
|
||||||
|
"mock_hass_config_yaml": "None",
|
||||||
"mock_zeroconf": "None",
|
"mock_zeroconf": "None",
|
||||||
"mqtt_client_mock": "MqttMockPahoClient",
|
"mqtt_client_mock": "MqttMockPahoClient",
|
||||||
"mqtt_mock": "MqttMockHAClient",
|
"mqtt_mock": "MqttMockHAClient",
|
||||||
|
@ -1,29 +1,39 @@
|
|||||||
"""The tests for the Event automation."""
|
"""The tests for the Event automation."""
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
import homeassistant.components.automation as automation
|
import homeassistant.components.automation as automation
|
||||||
from homeassistant.core import CoreState
|
from homeassistant.core import CoreState, HomeAssistant
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import async_mock_service
|
from tests.common import async_mock_service
|
||||||
|
|
||||||
|
|
||||||
async def test_if_fires_on_hass_start(hass):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
automation.DOMAIN: {
|
||||||
|
"alias": "hello",
|
||||||
|
"trigger": {"platform": "homeassistant", "event": "start"},
|
||||||
|
"action": {
|
||||||
|
"service": "test.automation",
|
||||||
|
"data_template": {"id": "{{ trigger.id}}"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_if_fires_on_hass_start(
|
||||||
|
hass: HomeAssistant, mock_hass_config: None, hass_config: ConfigType | None
|
||||||
|
) -> None:
|
||||||
"""Test the firing when Home Assistant starts."""
|
"""Test the firing when Home Assistant starts."""
|
||||||
calls = async_mock_service(hass, "test", "automation")
|
calls = async_mock_service(hass, "test", "automation")
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
config = {
|
|
||||||
automation.DOMAIN: {
|
|
||||||
"alias": "hello",
|
|
||||||
"trigger": {"platform": "homeassistant", "event": "start"},
|
|
||||||
"action": {
|
|
||||||
"service": "test.automation",
|
|
||||||
"data_template": {"id": "{{ trigger.id}}"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert await async_setup_component(hass, automation.DOMAIN, config)
|
assert await async_setup_component(hass, automation.DOMAIN, hass_config)
|
||||||
assert automation.is_on(hass, "automation.hello")
|
assert automation.is_on(hass, "automation.hello")
|
||||||
assert len(calls) == 0
|
assert len(calls) == 0
|
||||||
|
|
||||||
@ -32,13 +42,9 @@ async def test_if_fires_on_hass_start(hass):
|
|||||||
assert automation.is_on(hass, "automation.hello")
|
assert automation.is_on(hass, "automation.hello")
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1
|
||||||
|
|
||||||
with patch(
|
await hass.services.async_call(
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
automation.DOMAIN, automation.SERVICE_RELOAD, blocking=True
|
||||||
AsyncMock(return_value=config),
|
)
|
||||||
):
|
|
||||||
await hass.services.async_call(
|
|
||||||
automation.DOMAIN, automation.SERVICE_RELOAD, blocking=True
|
|
||||||
)
|
|
||||||
|
|
||||||
assert automation.is_on(hass, "automation.hello")
|
assert automation.is_on(hass, "automation.hello")
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Tests for the diagnostics data provided by the KNX integration."""
|
"""Tests for the diagnostics data provided by the KNX integration."""
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
from xknx.io import DEFAULT_MCAST_GRP, DEFAULT_MCAST_PORT
|
from xknx.io import DEFAULT_MCAST_GRP, DEFAULT_MCAST_PORT
|
||||||
|
|
||||||
from homeassistant.components.knx.const import (
|
from homeassistant.components.knx.const import (
|
||||||
@ -29,37 +29,40 @@ from tests.components.diagnostics import get_diagnostics_for_config_entry
|
|||||||
from tests.typing import ClientSessionGenerator
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{}])
|
||||||
async def test_diagnostics(
|
async def test_diagnostics(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
knx: KNXTestKit,
|
knx: KNXTestKit,
|
||||||
|
mock_hass_config: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test diagnostics."""
|
"""Test diagnostics."""
|
||||||
await knx.setup_integration({})
|
await knx.setup_integration({})
|
||||||
|
|
||||||
with patch("homeassistant.config.async_hass_config_yaml", return_value={}):
|
# Overwrite the version for this test since we don't want to change this with every library bump
|
||||||
# Overwrite the version for this test since we don't want to change this with every library bump
|
knx.xknx.version = "1.0.0"
|
||||||
knx.xknx.version = "1.0.0"
|
assert await get_diagnostics_for_config_entry(
|
||||||
assert await get_diagnostics_for_config_entry(
|
hass, hass_client, mock_config_entry
|
||||||
hass, hass_client, mock_config_entry
|
) == {
|
||||||
) == {
|
"config_entry_data": {
|
||||||
"config_entry_data": {
|
"connection_type": "automatic",
|
||||||
"connection_type": "automatic",
|
"individual_address": "0.0.240",
|
||||||
"individual_address": "0.0.240",
|
"multicast_group": "224.0.23.12",
|
||||||
"multicast_group": "224.0.23.12",
|
"multicast_port": 3671,
|
||||||
"multicast_port": 3671,
|
"rate_limit": 0,
|
||||||
"rate_limit": 0,
|
"state_updater": True,
|
||||||
"state_updater": True,
|
},
|
||||||
},
|
"configuration_error": None,
|
||||||
"configuration_error": None,
|
"configuration_yaml": None,
|
||||||
"configuration_yaml": None,
|
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
||||||
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{"knx": {"wrong_key": {}}}])
|
||||||
async def test_diagnostic_config_error(
|
async def test_diagnostic_config_error(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
mock_hass_config: None,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
knx: KNXTestKit,
|
knx: KNXTestKit,
|
||||||
@ -67,32 +70,30 @@ async def test_diagnostic_config_error(
|
|||||||
"""Test diagnostics."""
|
"""Test diagnostics."""
|
||||||
await knx.setup_integration({})
|
await knx.setup_integration({})
|
||||||
|
|
||||||
with patch(
|
# Overwrite the version for this test since we don't want to change this with every library bump
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
knx.xknx.version = "1.0.0"
|
||||||
return_value={"knx": {"wrong_key": {}}},
|
assert await get_diagnostics_for_config_entry(
|
||||||
):
|
hass, hass_client, mock_config_entry
|
||||||
# Overwrite the version for this test since we don't want to change this with every library bump
|
) == {
|
||||||
knx.xknx.version = "1.0.0"
|
"config_entry_data": {
|
||||||
assert await get_diagnostics_for_config_entry(
|
"connection_type": "automatic",
|
||||||
hass, hass_client, mock_config_entry
|
"individual_address": "0.0.240",
|
||||||
) == {
|
"multicast_group": "224.0.23.12",
|
||||||
"config_entry_data": {
|
"multicast_port": 3671,
|
||||||
"connection_type": "automatic",
|
"rate_limit": 0,
|
||||||
"individual_address": "0.0.240",
|
"state_updater": True,
|
||||||
"multicast_group": "224.0.23.12",
|
},
|
||||||
"multicast_port": 3671,
|
"configuration_error": "extra keys not allowed @ data['knx']['wrong_key']",
|
||||||
"rate_limit": 0,
|
"configuration_yaml": {"wrong_key": {}},
|
||||||
"state_updater": True,
|
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
||||||
},
|
}
|
||||||
"configuration_error": "extra keys not allowed @ data['knx']['wrong_key']",
|
|
||||||
"configuration_yaml": {"wrong_key": {}},
|
|
||||||
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{}])
|
||||||
async def test_diagnostic_redact(
|
async def test_diagnostic_redact(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
|
mock_hass_config: None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test diagnostics redacting data."""
|
"""Test diagnostics redacting data."""
|
||||||
mock_config_entry: MockConfigEntry = MockConfigEntry(
|
mock_config_entry: MockConfigEntry = MockConfigEntry(
|
||||||
@ -114,25 +115,24 @@ async def test_diagnostic_redact(
|
|||||||
knx: KNXTestKit = KNXTestKit(hass, mock_config_entry)
|
knx: KNXTestKit = KNXTestKit(hass, mock_config_entry)
|
||||||
await knx.setup_integration({})
|
await knx.setup_integration({})
|
||||||
|
|
||||||
with patch("homeassistant.config.async_hass_config_yaml", return_value={}):
|
# Overwrite the version for this test since we don't want to change this with every library bump
|
||||||
# Overwrite the version for this test since we don't want to change this with every library bump
|
knx.xknx.version = "1.0.0"
|
||||||
knx.xknx.version = "1.0.0"
|
assert await get_diagnostics_for_config_entry(
|
||||||
assert await get_diagnostics_for_config_entry(
|
hass, hass_client, mock_config_entry
|
||||||
hass, hass_client, mock_config_entry
|
) == {
|
||||||
) == {
|
"config_entry_data": {
|
||||||
"config_entry_data": {
|
"connection_type": "automatic",
|
||||||
"connection_type": "automatic",
|
"individual_address": "0.0.240",
|
||||||
"individual_address": "0.0.240",
|
"multicast_group": "224.0.23.12",
|
||||||
"multicast_group": "224.0.23.12",
|
"multicast_port": 3671,
|
||||||
"multicast_port": 3671,
|
"rate_limit": 0,
|
||||||
"rate_limit": 0,
|
"state_updater": True,
|
||||||
"state_updater": True,
|
"knxkeys_password": "**REDACTED**",
|
||||||
"knxkeys_password": "**REDACTED**",
|
"user_password": "**REDACTED**",
|
||||||
"user_password": "**REDACTED**",
|
"device_authentication": "**REDACTED**",
|
||||||
"device_authentication": "**REDACTED**",
|
"backbone_key": "**REDACTED**",
|
||||||
"backbone_key": "**REDACTED**",
|
},
|
||||||
},
|
"configuration_error": None,
|
||||||
"configuration_error": None,
|
"configuration_yaml": None,
|
||||||
"configuration_yaml": None,
|
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
||||||
"xknx": {"current_address": "0.0.0", "version": "1.0.0"},
|
}
|
||||||
}
|
|
||||||
|
@ -44,6 +44,7 @@ from homeassistant.components.websocket_api.auth import (
|
|||||||
TYPE_AUTH_REQUIRED,
|
TYPE_AUTH_REQUIRED,
|
||||||
)
|
)
|
||||||
from homeassistant.components.websocket_api.http import URL
|
from homeassistant.components.websocket_api.http import URL
|
||||||
|
from homeassistant.config import YAML_CONFIG_FILE
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import HASSIO_USER_NAME
|
from homeassistant.const import HASSIO_USER_NAME
|
||||||
from homeassistant.core import CoreState, HomeAssistant
|
from homeassistant.core import CoreState, HomeAssistant
|
||||||
@ -90,6 +91,7 @@ from .common import ( # noqa: E402, isort:skip
|
|||||||
get_test_home_assistant,
|
get_test_home_assistant,
|
||||||
init_recorder_component,
|
init_recorder_component,
|
||||||
mock_storage,
|
mock_storage,
|
||||||
|
patch_yaml_files,
|
||||||
)
|
)
|
||||||
from .test_util.aiohttp import ( # noqa: E402, isort:skip
|
from .test_util.aiohttp import ( # noqa: E402, isort:skip
|
||||||
AiohttpClientMocker,
|
AiohttpClientMocker,
|
||||||
@ -917,6 +919,66 @@ async def _mqtt_mock_entry(
|
|||||||
yield _setup_mqtt_entry
|
yield _setup_mqtt_entry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hass_config() -> ConfigType | None:
|
||||||
|
"""Fixture to parametrize the content of main configuration using mock_hass_config.
|
||||||
|
|
||||||
|
To set a configuration, tests can be marked with:
|
||||||
|
@pytest.mark.parametrize("hass_config", [{integration: {...}}])
|
||||||
|
Add the `mock_hass_config: None` fixture to the test.
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_hass_config(
|
||||||
|
hass: HomeAssistant, hass_config: ConfigType | None
|
||||||
|
) -> Generator[None, None, None]:
|
||||||
|
"""Fixture to mock the content of main configuration.
|
||||||
|
|
||||||
|
Patches homeassistant.config.load_yaml_config_file with `hass_config` parameterized as content.
|
||||||
|
"""
|
||||||
|
with patch("homeassistant.config.load_yaml_config_file", return_value=hass_config):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hass_config_yaml() -> str | None:
|
||||||
|
"""Fixture to parametrize the content of configuration.yaml file.
|
||||||
|
|
||||||
|
To set yaml content, tests can be marked with:
|
||||||
|
@pytest.mark.parametrize("hass_config_yaml", ["..."])
|
||||||
|
Add the `mock_hass_config_yaml: None` fixture to the test.
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hass_config_yaml_files(hass_config_yaml: str | None) -> dict[str, str] | None:
|
||||||
|
"""Fixture to parametrize multiple yaml configuration files.
|
||||||
|
|
||||||
|
To set the YAML files to patch, tests can be marked with:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files", [{"configuration.yaml": "..."}]
|
||||||
|
)
|
||||||
|
Add the `mock_hass_config_yaml: None` fixture to the test.
|
||||||
|
"""
|
||||||
|
return None if hass_config_yaml is None else {YAML_CONFIG_FILE: hass_config_yaml}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_hass_config_yaml(
|
||||||
|
hass: HomeAssistant, hass_config_yaml_files: dict[str, str] | None
|
||||||
|
) -> Generator[None, None, None]:
|
||||||
|
"""Fixture to mock the content of the yaml configuration files.
|
||||||
|
|
||||||
|
Patches yaml configuration files using the `hass_config_yaml`
|
||||||
|
and `hass_config_yaml_files` fixtures.
|
||||||
|
"""
|
||||||
|
with patch_yaml_files(hass_config_yaml_files):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def mqtt_mock_entry_no_yaml_config(
|
async def mqtt_mock_entry_no_yaml_config(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -6,7 +6,7 @@ import pytest
|
|||||||
from homeassistant.config import YAML_CONFIG_FILE
|
from homeassistant.config import YAML_CONFIG_FILE
|
||||||
import homeassistant.scripts.check_config as check_config
|
import homeassistant.scripts.check_config as check_config
|
||||||
|
|
||||||
from tests.common import get_test_config_dir, patch_yaml_files
|
from tests.common import get_test_config_dir
|
||||||
|
|
||||||
BASE_CONFIG = (
|
BASE_CONFIG = (
|
||||||
"homeassistant:\n"
|
"homeassistant:\n"
|
||||||
@ -43,114 +43,118 @@ def normalize_yaml_files(check_dict):
|
|||||||
return [key.replace(root, "...") for key in sorted(check_dict["yaml_files"].keys())]
|
return [key.replace(root, "...") for key in sorted(check_dict["yaml_files"].keys())]
|
||||||
|
|
||||||
|
|
||||||
def test_bad_core_config(mock_is_file, event_loop) -> None:
|
@pytest.mark.parametrize("hass_config_yaml", [BAD_CORE_CONFIG])
|
||||||
|
def test_bad_core_config(mock_is_file, event_loop, mock_hass_config_yaml: None) -> None:
|
||||||
"""Test a bad core config setup."""
|
"""Test a bad core config setup."""
|
||||||
files = {YAML_CONFIG_FILE: BAD_CORE_CONFIG}
|
res = check_config.check(get_test_config_dir())
|
||||||
with patch_yaml_files(files):
|
assert res["except"].keys() == {"homeassistant"}
|
||||||
res = check_config.check(get_test_config_dir())
|
assert res["except"]["homeassistant"][1] == {"unit_system": "bad"}
|
||||||
assert res["except"].keys() == {"homeassistant"}
|
|
||||||
assert res["except"]["homeassistant"][1] == {"unit_system": "bad"}
|
|
||||||
|
|
||||||
|
|
||||||
def test_config_platform_valid(mock_is_file, event_loop) -> None:
|
@pytest.mark.parametrize("hass_config_yaml", [BASE_CONFIG + "light:\n platform: demo"])
|
||||||
|
def test_config_platform_valid(
|
||||||
|
mock_is_file, event_loop, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test a valid platform setup."""
|
"""Test a valid platform setup."""
|
||||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: demo"}
|
res = check_config.check(get_test_config_dir())
|
||||||
with patch_yaml_files(files):
|
assert res["components"].keys() == {"homeassistant", "light"}
|
||||||
res = check_config.check(get_test_config_dir())
|
assert res["components"]["light"] == [{"platform": "demo"}]
|
||||||
assert res["components"].keys() == {"homeassistant", "light"}
|
assert res["except"] == {}
|
||||||
assert res["components"]["light"] == [{"platform": "demo"}]
|
assert res["secret_cache"] == {}
|
||||||
assert res["except"] == {}
|
assert res["secrets"] == {}
|
||||||
assert res["secret_cache"] == {}
|
assert len(res["yaml_files"]) == 1
|
||||||
assert res["secrets"] == {}
|
|
||||||
assert len(res["yaml_files"]) == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_component_platform_not_found(mock_is_file, event_loop) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
("hass_config_yaml", "platforms", "error"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
BASE_CONFIG + "beer:",
|
||||||
|
{"homeassistant"},
|
||||||
|
"Integration error: beer - Integration 'beer' not found.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
BASE_CONFIG + "light:\n platform: beer",
|
||||||
|
{"homeassistant", "light"},
|
||||||
|
"Platform error light.beer - Integration 'beer' not found.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_component_platform_not_found(
|
||||||
|
mock_is_file, event_loop, mock_hass_config_yaml: None, platforms, error
|
||||||
|
) -> None:
|
||||||
"""Test errors if component or platform not found."""
|
"""Test errors if component or platform not found."""
|
||||||
# Make sure they don't exist
|
# Make sure they don't exist
|
||||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
|
res = check_config.check(get_test_config_dir())
|
||||||
with patch_yaml_files(files):
|
assert res["components"].keys() == platforms
|
||||||
res = check_config.check(get_test_config_dir())
|
assert res["except"] == {check_config.ERROR_STR: [error]}
|
||||||
assert res["components"].keys() == {"homeassistant"}
|
assert res["secret_cache"] == {}
|
||||||
assert res["except"] == {
|
assert res["secrets"] == {}
|
||||||
check_config.ERROR_STR: [
|
assert len(res["yaml_files"]) == 1
|
||||||
"Integration error: beer - Integration 'beer' not found."
|
|
||||||
]
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
get_test_config_dir(YAML_CONFIG_FILE): BASE_CONFIG
|
||||||
|
+ "http:\n cors_allowed_origins: !secret http_pw",
|
||||||
|
get_test_config_dir(
|
||||||
|
"secrets.yaml"
|
||||||
|
): "logger: debug\nhttp_pw: http://google.com",
|
||||||
}
|
}
|
||||||
assert res["secret_cache"] == {}
|
],
|
||||||
assert res["secrets"] == {}
|
)
|
||||||
assert len(res["yaml_files"]) == 1
|
def test_secrets(mock_is_file, event_loop, mock_hass_config_yaml: None) -> None:
|
||||||
|
|
||||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: beer"}
|
|
||||||
with patch_yaml_files(files):
|
|
||||||
res = check_config.check(get_test_config_dir())
|
|
||||||
assert res["components"].keys() == {"homeassistant", "light"}
|
|
||||||
assert res["components"]["light"] == []
|
|
||||||
assert res["except"] == {
|
|
||||||
check_config.ERROR_STR: [
|
|
||||||
"Platform error light.beer - Integration 'beer' not found."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
assert res["secret_cache"] == {}
|
|
||||||
assert res["secrets"] == {}
|
|
||||||
assert len(res["yaml_files"]) == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_secrets(mock_is_file, event_loop) -> None:
|
|
||||||
"""Test secrets config checking method."""
|
"""Test secrets config checking method."""
|
||||||
secrets_path = get_test_config_dir("secrets.yaml")
|
res = check_config.check(get_test_config_dir(), True)
|
||||||
|
|
||||||
files = {
|
assert res["except"] == {}
|
||||||
get_test_config_dir(YAML_CONFIG_FILE): BASE_CONFIG
|
assert res["components"].keys() == {"homeassistant", "http"}
|
||||||
+ "http:\n cors_allowed_origins: !secret http_pw",
|
assert res["components"]["http"] == {
|
||||||
secrets_path: "logger: debug\nhttp_pw: http://google.com",
|
"cors_allowed_origins": ["http://google.com"],
|
||||||
|
"ip_ban_enabled": True,
|
||||||
|
"login_attempts_threshold": -1,
|
||||||
|
"server_port": 8123,
|
||||||
|
"ssl_profile": "modern",
|
||||||
}
|
}
|
||||||
|
assert res["secret_cache"] == {
|
||||||
with patch_yaml_files(files):
|
get_test_config_dir("secrets.yaml"): {"http_pw": "http://google.com"}
|
||||||
res = check_config.check(get_test_config_dir(), True)
|
}
|
||||||
|
assert res["secrets"] == {"http_pw": "http://google.com"}
|
||||||
assert res["except"] == {}
|
assert normalize_yaml_files(res) == [
|
||||||
assert res["components"].keys() == {"homeassistant", "http"}
|
".../configuration.yaml",
|
||||||
assert res["components"]["http"] == {
|
".../secrets.yaml",
|
||||||
"cors_allowed_origins": ["http://google.com"],
|
]
|
||||||
"ip_ban_enabled": True,
|
|
||||||
"login_attempts_threshold": -1,
|
|
||||||
"server_port": 8123,
|
|
||||||
"ssl_profile": "modern",
|
|
||||||
}
|
|
||||||
assert res["secret_cache"] == {secrets_path: {"http_pw": "http://google.com"}}
|
|
||||||
assert res["secrets"] == {"http_pw": "http://google.com"}
|
|
||||||
assert normalize_yaml_files(res) == [
|
|
||||||
".../configuration.yaml",
|
|
||||||
".../secrets.yaml",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def test_package_invalid(mock_is_file, event_loop) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml", [BASE_CONFIG + ' packages:\n p1:\n group: ["a"]']
|
||||||
|
)
|
||||||
|
def test_package_invalid(mock_is_file, event_loop, mock_hass_config_yaml: None) -> None:
|
||||||
"""Test an invalid package."""
|
"""Test an invalid package."""
|
||||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + ' packages:\n p1:\n group: ["a"]'}
|
res = check_config.check(get_test_config_dir())
|
||||||
with patch_yaml_files(files):
|
|
||||||
res = check_config.check(get_test_config_dir())
|
|
||||||
|
|
||||||
assert res["except"].keys() == {"homeassistant.packages.p1.group"}
|
assert res["except"].keys() == {"homeassistant.packages.p1.group"}
|
||||||
assert res["except"]["homeassistant.packages.p1.group"][1] == {"group": ["a"]}
|
assert res["except"]["homeassistant.packages.p1.group"][1] == {"group": ["a"]}
|
||||||
assert len(res["except"]) == 1
|
assert len(res["except"]) == 1
|
||||||
assert res["components"].keys() == {"homeassistant"}
|
assert res["components"].keys() == {"homeassistant"}
|
||||||
assert len(res["components"]) == 1
|
assert len(res["components"]) == 1
|
||||||
assert res["secret_cache"] == {}
|
assert res["secret_cache"] == {}
|
||||||
assert res["secrets"] == {}
|
assert res["secrets"] == {}
|
||||||
assert len(res["yaml_files"]) == 1
|
assert len(res["yaml_files"]) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_bootstrap_error(event_loop) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml", [BASE_CONFIG + "automation: !include no.yaml"]
|
||||||
|
)
|
||||||
|
def test_bootstrap_error(event_loop, mock_hass_config_yaml: None) -> None:
|
||||||
"""Test a valid platform setup."""
|
"""Test a valid platform setup."""
|
||||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "automation: !include no.yaml"}
|
res = check_config.check(get_test_config_dir(YAML_CONFIG_FILE))
|
||||||
with patch_yaml_files(files):
|
err = res["except"].pop(check_config.ERROR_STR)
|
||||||
res = check_config.check(get_test_config_dir(YAML_CONFIG_FILE))
|
assert len(err) == 1
|
||||||
err = res["except"].pop(check_config.ERROR_STR)
|
assert res["except"] == {}
|
||||||
assert len(err) == 1
|
assert res["components"] == {} # No components, load failed
|
||||||
assert res["except"] == {}
|
assert res["secret_cache"] == {}
|
||||||
assert res["components"] == {} # No components, load failed
|
assert res["secrets"] == {}
|
||||||
assert res["secret_cache"] == {}
|
assert res["yaml_files"] == {}
|
||||||
assert res["secrets"] == {}
|
|
||||||
assert res["yaml_files"] == {}
|
|
||||||
|
@ -454,7 +454,9 @@ def mock_ensure_config_exists():
|
|||||||
yield ensure_config_exists
|
yield ensure_config_exists
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{"browser": {}, "frontend": {}}])
|
||||||
async def test_setup_hass(
|
async def test_setup_hass(
|
||||||
|
mock_hass_config: None,
|
||||||
mock_enable_logging,
|
mock_enable_logging,
|
||||||
mock_is_virtual_env,
|
mock_is_virtual_env,
|
||||||
mock_mount_local_lib_path,
|
mock_mount_local_lib_path,
|
||||||
@ -462,17 +464,14 @@ async def test_setup_hass(
|
|||||||
mock_process_ha_config_upgrade,
|
mock_process_ha_config_upgrade,
|
||||||
caplog,
|
caplog,
|
||||||
event_loop,
|
event_loop,
|
||||||
):
|
) -> None:
|
||||||
"""Test it works."""
|
"""Test it works."""
|
||||||
verbose = Mock()
|
verbose = Mock()
|
||||||
log_rotate_days = Mock()
|
log_rotate_days = Mock()
|
||||||
log_file = Mock()
|
log_file = Mock()
|
||||||
log_no_color = Mock()
|
log_no_color = Mock()
|
||||||
|
|
||||||
with patch(
|
with patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 5000):
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
|
||||||
return_value={"browser": {}, "frontend": {}},
|
|
||||||
), patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 5000):
|
|
||||||
hass = await bootstrap.async_setup_hass(
|
hass = await bootstrap.async_setup_hass(
|
||||||
runner.RuntimeConfig(
|
runner.RuntimeConfig(
|
||||||
config_dir=get_test_config_dir(),
|
config_dir=get_test_config_dir(),
|
||||||
@ -505,7 +504,9 @@ async def test_setup_hass(
|
|||||||
assert hass == async_get_hass()
|
assert hass == async_get_hass()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{"browser": {}, "frontend": {}}])
|
||||||
async def test_setup_hass_takes_longer_than_log_slow_startup(
|
async def test_setup_hass_takes_longer_than_log_slow_startup(
|
||||||
|
mock_hass_config: None,
|
||||||
mock_enable_logging,
|
mock_enable_logging,
|
||||||
mock_is_virtual_env,
|
mock_is_virtual_env,
|
||||||
mock_mount_local_lib_path,
|
mock_mount_local_lib_path,
|
||||||
@ -513,7 +514,7 @@ async def test_setup_hass_takes_longer_than_log_slow_startup(
|
|||||||
mock_process_ha_config_upgrade,
|
mock_process_ha_config_upgrade,
|
||||||
caplog,
|
caplog,
|
||||||
event_loop,
|
event_loop,
|
||||||
):
|
) -> None:
|
||||||
"""Test it works."""
|
"""Test it works."""
|
||||||
verbose = Mock()
|
verbose = Mock()
|
||||||
log_rotate_days = Mock()
|
log_rotate_days = Mock()
|
||||||
@ -524,10 +525,7 @@ async def test_setup_hass_takes_longer_than_log_slow_startup(
|
|||||||
await asyncio.sleep(0.6)
|
await asyncio.sleep(0.6)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
with patch(
|
with patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 0.3), patch.object(
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
|
||||||
return_value={"browser": {}, "frontend": {}},
|
|
||||||
), patch.object(bootstrap, "LOG_SLOW_STARTUP_INTERVAL", 0.3), patch.object(
|
|
||||||
bootstrap, "SLOW_STARTUP_CHECK_INTERVAL", 0.05
|
bootstrap, "SLOW_STARTUP_CHECK_INTERVAL", 0.05
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.frontend.async_setup",
|
"homeassistant.components.frontend.async_setup",
|
||||||
@ -555,7 +553,7 @@ async def test_setup_hass_invalid_yaml(
|
|||||||
mock_ensure_config_exists,
|
mock_ensure_config_exists,
|
||||||
mock_process_ha_config_upgrade,
|
mock_process_ha_config_upgrade,
|
||||||
event_loop,
|
event_loop,
|
||||||
):
|
) -> None:
|
||||||
"""Test it works."""
|
"""Test it works."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.config.async_hass_config_yaml", side_effect=HomeAssistantError
|
"homeassistant.config.async_hass_config_yaml", side_effect=HomeAssistantError
|
||||||
@ -636,70 +634,71 @@ async def test_setup_hass_safe_mode(
|
|||||||
assert len(browser_setup.mock_calls) == 0
|
assert len(browser_setup.mock_calls) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("hass_config", [{"homeassistant": {"non-existing": 1}}])
|
||||||
async def test_setup_hass_invalid_core_config(
|
async def test_setup_hass_invalid_core_config(
|
||||||
|
mock_hass_config: None,
|
||||||
mock_enable_logging,
|
mock_enable_logging,
|
||||||
mock_is_virtual_env,
|
mock_is_virtual_env,
|
||||||
mock_mount_local_lib_path,
|
mock_mount_local_lib_path,
|
||||||
mock_ensure_config_exists,
|
mock_ensure_config_exists,
|
||||||
mock_process_ha_config_upgrade,
|
mock_process_ha_config_upgrade,
|
||||||
event_loop,
|
event_loop,
|
||||||
):
|
) -> None:
|
||||||
"""Test it works."""
|
"""Test it works."""
|
||||||
with patch(
|
hass = await bootstrap.async_setup_hass(
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
runner.RuntimeConfig(
|
||||||
return_value={"homeassistant": {"non-existing": 1}},
|
config_dir=get_test_config_dir(),
|
||||||
):
|
verbose=False,
|
||||||
hass = await bootstrap.async_setup_hass(
|
log_rotate_days=10,
|
||||||
runner.RuntimeConfig(
|
log_file="",
|
||||||
config_dir=get_test_config_dir(),
|
log_no_color=False,
|
||||||
verbose=False,
|
skip_pip=True,
|
||||||
log_rotate_days=10,
|
safe_mode=False,
|
||||||
log_file="",
|
),
|
||||||
log_no_color=False,
|
)
|
||||||
skip_pip=True,
|
|
||||||
safe_mode=False,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
assert "safe_mode" in hass.config.components
|
assert "safe_mode" in hass.config.components
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_safe_mode_if_no_frontend(
|
@pytest.mark.parametrize(
|
||||||
mock_enable_logging,
|
"hass_config",
|
||||||
mock_is_virtual_env,
|
[
|
||||||
mock_mount_local_lib_path,
|
{
|
||||||
mock_ensure_config_exists,
|
|
||||||
mock_process_ha_config_upgrade,
|
|
||||||
event_loop,
|
|
||||||
):
|
|
||||||
"""Test we setup safe mode if frontend didn't load."""
|
|
||||||
verbose = Mock()
|
|
||||||
log_rotate_days = Mock()
|
|
||||||
log_file = Mock()
|
|
||||||
log_no_color = Mock()
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.config.async_hass_config_yaml",
|
|
||||||
return_value={
|
|
||||||
"homeassistant": {
|
"homeassistant": {
|
||||||
"internal_url": "http://192.168.1.100:8123",
|
"internal_url": "http://192.168.1.100:8123",
|
||||||
"external_url": "https://abcdef.ui.nabu.casa",
|
"external_url": "https://abcdef.ui.nabu.casa",
|
||||||
},
|
},
|
||||||
"map": {},
|
"map": {},
|
||||||
"person": {"invalid": True},
|
"person": {"invalid": True},
|
||||||
},
|
}
|
||||||
):
|
],
|
||||||
hass = await bootstrap.async_setup_hass(
|
)
|
||||||
runner.RuntimeConfig(
|
async def test_setup_safe_mode_if_no_frontend(
|
||||||
config_dir=get_test_config_dir(),
|
mock_hass_config: None,
|
||||||
verbose=verbose,
|
mock_enable_logging,
|
||||||
log_rotate_days=log_rotate_days,
|
mock_is_virtual_env,
|
||||||
log_file=log_file,
|
mock_mount_local_lib_path,
|
||||||
log_no_color=log_no_color,
|
mock_ensure_config_exists,
|
||||||
skip_pip=True,
|
mock_process_ha_config_upgrade,
|
||||||
safe_mode=False,
|
event_loop,
|
||||||
),
|
) -> None:
|
||||||
)
|
"""Test we setup safe mode if frontend didn't load."""
|
||||||
|
verbose = Mock()
|
||||||
|
log_rotate_days = Mock()
|
||||||
|
log_file = Mock()
|
||||||
|
log_no_color = Mock()
|
||||||
|
|
||||||
|
hass = await bootstrap.async_setup_hass(
|
||||||
|
runner.RuntimeConfig(
|
||||||
|
config_dir=get_test_config_dir(),
|
||||||
|
verbose=verbose,
|
||||||
|
log_rotate_days=log_rotate_days,
|
||||||
|
log_file=log_file,
|
||||||
|
log_no_color=log_no_color,
|
||||||
|
skip_pip=True,
|
||||||
|
safe_mode=False,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
assert "safe_mode" in hass.config.components
|
assert "safe_mode" in hass.config.components
|
||||||
assert hass.config.config_dir == get_test_config_dir()
|
assert hass.config.config_dir == get_test_config_dir()
|
||||||
|
@ -40,7 +40,7 @@ from homeassistant.util.unit_system import (
|
|||||||
)
|
)
|
||||||
from homeassistant.util.yaml import SECRET_YAML
|
from homeassistant.util.yaml import SECRET_YAML
|
||||||
|
|
||||||
from .common import MockUser, get_test_config_dir, patch_yaml_files
|
from .common import MockUser, get_test_config_dir
|
||||||
|
|
||||||
CONFIG_DIR = get_test_config_dir()
|
CONFIG_DIR = get_test_config_dir()
|
||||||
YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE)
|
YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE)
|
||||||
@ -736,20 +736,25 @@ async def test_check_ha_config_file_wrong(mock_check, hass):
|
|||||||
assert await config_util.async_check_ha_config_file(hass) == "bad"
|
assert await config_util.async_check_ha_config_file(hass) == "bad"
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.config.os.path.isfile", mock.Mock(return_value=True))
|
@pytest.mark.parametrize(
|
||||||
async def test_async_hass_config_yaml_merge(merge_log_err, hass):
|
"hass_config",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
config_util.CONF_CORE: {
|
||||||
|
config_util.CONF_PACKAGES: {
|
||||||
|
"pack_dict": {"input_boolean": {"ib1": None}}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"input_boolean": {"ib2": None},
|
||||||
|
"light": {"platform": "test"},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_async_hass_config_yaml_merge(
|
||||||
|
merge_log_err, hass: HomeAssistant, mock_hass_config: None
|
||||||
|
) -> None:
|
||||||
"""Test merge during async config reload."""
|
"""Test merge during async config reload."""
|
||||||
config = {
|
conf = await config_util.async_hass_config_yaml(hass)
|
||||||
config_util.CONF_CORE: {
|
|
||||||
config_util.CONF_PACKAGES: {"pack_dict": {"input_boolean": {"ib1": None}}}
|
|
||||||
},
|
|
||||||
"input_boolean": {"ib2": None},
|
|
||||||
"light": {"platform": "test"},
|
|
||||||
}
|
|
||||||
|
|
||||||
files = {config_util.YAML_CONFIG_FILE: yaml.dump(config)}
|
|
||||||
with patch_yaml_files(files, True):
|
|
||||||
conf = await config_util.async_hass_config_yaml(hass)
|
|
||||||
|
|
||||||
assert merge_log_err.call_count == 0
|
assert merge_log_err.call_count == 0
|
||||||
assert conf[config_util.CONF_CORE].get(config_util.CONF_PACKAGES) is not None
|
assert conf[config_util.CONF_CORE].get(config_util.CONF_PACKAGES) is not None
|
||||||
|
@ -3,6 +3,7 @@ import importlib
|
|||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
from typing import Any
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@ -67,17 +68,17 @@ def test_simple_dict(try_both_loaders):
|
|||||||
assert doc["key"] == "value"
|
assert doc["key"] == "value"
|
||||||
|
|
||||||
|
|
||||||
def test_unhashable_key() -> None:
|
@pytest.mark.parametrize("hass_config_yaml", ["message:\n {{ states.state }}"])
|
||||||
|
def test_unhashable_key(mock_hass_config_yaml: None) -> None:
|
||||||
"""Test an unhashable key."""
|
"""Test an unhashable key."""
|
||||||
files = {YAML_CONFIG_FILE: "message:\n {{ states.state }}"}
|
with pytest.raises(HomeAssistantError):
|
||||||
with pytest.raises(HomeAssistantError), patch_yaml_files(files):
|
|
||||||
load_yaml_config_file(YAML_CONFIG_FILE)
|
load_yaml_config_file(YAML_CONFIG_FILE)
|
||||||
|
|
||||||
|
|
||||||
def test_no_key(try_both_loaders):
|
@pytest.mark.parametrize("hass_config_yaml", ["a: a\nnokeyhere"])
|
||||||
|
def test_no_key(try_both_loaders, mock_hass_config_yaml: None) -> None:
|
||||||
"""Test item without a key."""
|
"""Test item without a key."""
|
||||||
files = {YAML_CONFIG_FILE: "a: a\nnokeyhere"}
|
with pytest.raises(HomeAssistantError):
|
||||||
with pytest.raises(HomeAssistantError), patch_yaml_files(files):
|
|
||||||
yaml.load_yaml(YAML_CONFIG_FILE)
|
yaml.load_yaml(YAML_CONFIG_FILE)
|
||||||
|
|
||||||
|
|
||||||
@ -106,35 +107,50 @@ def test_invalid_environment_variable(try_both_loaders):
|
|||||||
yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
|
|
||||||
|
|
||||||
def test_include_yaml(try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
("hass_config_yaml_files", "value"),
|
||||||
|
[({"test.yaml": "value"}, "value"), ({"test.yaml": None}, {})],
|
||||||
|
)
|
||||||
|
def test_include_yaml(
|
||||||
|
try_both_loaders, mock_hass_config_yaml: None, value: Any
|
||||||
|
) -> None:
|
||||||
"""Test include yaml."""
|
"""Test include yaml."""
|
||||||
with patch_yaml_files({"test.yaml": "value"}):
|
conf = "key: !include test.yaml"
|
||||||
conf = "key: !include test.yaml"
|
with io.StringIO(conf) as file:
|
||||||
with io.StringIO(conf) as file:
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
assert doc["key"] == value
|
||||||
assert doc["key"] == "value"
|
|
||||||
|
|
||||||
with patch_yaml_files({"test.yaml": None}):
|
|
||||||
conf = "key: !include test.yaml"
|
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert doc["key"] == {}
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_list(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files", [{"/test/one.yaml": "one", "/test/two.yaml": "two"}]
|
||||||
|
)
|
||||||
|
def test_include_dir_list(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir list yaml."""
|
"""Test include dir list yaml."""
|
||||||
mock_walk.return_value = [["/test", [], ["two.yaml", "one.yaml"]]]
|
mock_walk.return_value = [["/test", [], ["two.yaml", "one.yaml"]]]
|
||||||
|
|
||||||
with patch_yaml_files({"/test/one.yaml": "one", "/test/two.yaml": "two"}):
|
conf = "key: !include_dir_list /test"
|
||||||
conf = "key: !include_dir_list /test"
|
with io.StringIO(conf) as file:
|
||||||
with io.StringIO(conf) as file:
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
assert doc["key"] == sorted(["one", "two"])
|
||||||
assert doc["key"] == sorted(["one", "two"])
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_list_recursive(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/test/zero.yaml": "zero",
|
||||||
|
"/test/tmp2/one.yaml": "one",
|
||||||
|
"/test/tmp2/two.yaml": "two",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_include_dir_list_recursive(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir recursive list yaml."""
|
"""Test include dir recursive list yaml."""
|
||||||
mock_walk.return_value = [
|
mock_walk.return_value = [
|
||||||
["/test", ["tmp2", ".ignore", "ignore"], ["zero.yaml"]],
|
["/test", ["tmp2", ".ignore", "ignore"], ["zero.yaml"]],
|
||||||
@ -142,41 +158,49 @@ def test_include_dir_list_recursive(mock_walk, try_both_loaders):
|
|||||||
["/test/ignore", [], [".ignore.yaml"]],
|
["/test/ignore", [], [".ignore.yaml"]],
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch_yaml_files(
|
conf = "key: !include_dir_list /test"
|
||||||
{
|
with io.StringIO(conf) as file:
|
||||||
"/test/zero.yaml": "zero",
|
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
|
||||||
"/test/tmp2/one.yaml": "one",
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
"/test/tmp2/two.yaml": "two",
|
assert "tmp2" in mock_walk.return_value[0][1]
|
||||||
}
|
assert ".ignore" not in mock_walk.return_value[0][1]
|
||||||
):
|
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
|
||||||
conf = "key: !include_dir_list /test"
|
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
assert (
|
|
||||||
".ignore" in mock_walk.return_value[0][1]
|
|
||||||
), "Expecting .ignore in here"
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert "tmp2" in mock_walk.return_value[0][1]
|
|
||||||
assert ".ignore" not in mock_walk.return_value[0][1]
|
|
||||||
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_named(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[{"/test/first.yaml": "one", "/test/second.yaml": "two"}],
|
||||||
|
)
|
||||||
|
def test_include_dir_named(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir named yaml."""
|
"""Test include dir named yaml."""
|
||||||
mock_walk.return_value = [
|
mock_walk.return_value = [
|
||||||
["/test", [], ["first.yaml", "second.yaml", "secrets.yaml"]]
|
["/test", [], ["first.yaml", "second.yaml", "secrets.yaml"]]
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch_yaml_files({"/test/first.yaml": "one", "/test/second.yaml": "two"}):
|
conf = "key: !include_dir_named /test"
|
||||||
conf = "key: !include_dir_named /test"
|
correct = {"first": "one", "second": "two"}
|
||||||
correct = {"first": "one", "second": "two"}
|
with io.StringIO(conf) as file:
|
||||||
with io.StringIO(conf) as file:
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
assert doc["key"] == correct
|
||||||
assert doc["key"] == correct
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_named_recursive(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/test/first.yaml": "one",
|
||||||
|
"/test/tmp2/second.yaml": "two",
|
||||||
|
"/test/tmp2/third.yaml": "three",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_include_dir_named_recursive(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir named yaml."""
|
"""Test include dir named yaml."""
|
||||||
mock_walk.return_value = [
|
mock_walk.return_value = [
|
||||||
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
||||||
@ -184,85 +208,99 @@ def test_include_dir_named_recursive(mock_walk, try_both_loaders):
|
|||||||
["/test/ignore", [], [".ignore.yaml"]],
|
["/test/ignore", [], [".ignore.yaml"]],
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch_yaml_files(
|
conf = "key: !include_dir_named /test"
|
||||||
{
|
correct = {"first": "one", "second": "two", "third": "three"}
|
||||||
"/test/first.yaml": "one",
|
with io.StringIO(conf) as file:
|
||||||
"/test/tmp2/second.yaml": "two",
|
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
|
||||||
"/test/tmp2/third.yaml": "three",
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
}
|
assert "tmp2" in mock_walk.return_value[0][1]
|
||||||
):
|
assert ".ignore" not in mock_walk.return_value[0][1]
|
||||||
conf = "key: !include_dir_named /test"
|
assert doc["key"] == correct
|
||||||
correct = {"first": "one", "second": "two", "third": "three"}
|
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
assert (
|
|
||||||
".ignore" in mock_walk.return_value[0][1]
|
|
||||||
), "Expecting .ignore in here"
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert "tmp2" in mock_walk.return_value[0][1]
|
|
||||||
assert ".ignore" not in mock_walk.return_value[0][1]
|
|
||||||
assert doc["key"] == correct
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_merge_list(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[{"/test/first.yaml": "- one", "/test/second.yaml": "- two\n- three"}],
|
||||||
|
)
|
||||||
|
def test_include_dir_merge_list(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir merge list yaml."""
|
"""Test include dir merge list yaml."""
|
||||||
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
|
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
|
||||||
|
|
||||||
with patch_yaml_files(
|
conf = "key: !include_dir_merge_list /test"
|
||||||
{"/test/first.yaml": "- one", "/test/second.yaml": "- two\n- three"}
|
with io.StringIO(conf) as file:
|
||||||
):
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
conf = "key: !include_dir_merge_list /test"
|
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_merge_list_recursive(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
"""Test include dir merge list yaml."""
|
"hass_config_yaml_files",
|
||||||
mock_walk.return_value = [
|
[
|
||||||
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
|
||||||
["/test/tmp2", [], ["second.yaml", "third.yaml"]],
|
|
||||||
["/test/ignore", [], [".ignore.yaml"]],
|
|
||||||
]
|
|
||||||
|
|
||||||
with patch_yaml_files(
|
|
||||||
{
|
{
|
||||||
"/test/first.yaml": "- one",
|
"/test/first.yaml": "- one",
|
||||||
"/test/tmp2/second.yaml": "- two",
|
"/test/tmp2/second.yaml": "- two",
|
||||||
"/test/tmp2/third.yaml": "- three\n- four",
|
"/test/tmp2/third.yaml": "- three\n- four",
|
||||||
}
|
}
|
||||||
):
|
],
|
||||||
conf = "key: !include_dir_merge_list /test"
|
)
|
||||||
with io.StringIO(conf) as file:
|
def test_include_dir_merge_list_recursive(
|
||||||
assert (
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
".ignore" in mock_walk.return_value[0][1]
|
) -> None:
|
||||||
), "Expecting .ignore in here"
|
"""Test include dir merge list yaml."""
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
mock_walk.return_value = [
|
||||||
assert "tmp2" in mock_walk.return_value[0][1]
|
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
||||||
assert ".ignore" not in mock_walk.return_value[0][1]
|
["/test/tmp2", [], ["second.yaml", "third.yaml"]],
|
||||||
assert sorted(doc["key"]) == sorted(["one", "two", "three", "four"])
|
["/test/ignore", [], [".ignore.yaml"]],
|
||||||
|
]
|
||||||
|
|
||||||
|
conf = "key: !include_dir_merge_list /test"
|
||||||
|
with io.StringIO(conf) as file:
|
||||||
|
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
|
||||||
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
|
assert "tmp2" in mock_walk.return_value[0][1]
|
||||||
|
assert ".ignore" not in mock_walk.return_value[0][1]
|
||||||
|
assert sorted(doc["key"]) == sorted(["one", "two", "three", "four"])
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_merge_named(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/test/first.yaml": "key1: one",
|
||||||
|
"/test/second.yaml": "key2: two\nkey3: three",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_include_dir_merge_named(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir merge named yaml."""
|
"""Test include dir merge named yaml."""
|
||||||
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
|
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
|
||||||
|
|
||||||
files = {
|
conf = "key: !include_dir_merge_named /test"
|
||||||
"/test/first.yaml": "key1: one",
|
with io.StringIO(conf) as file:
|
||||||
"/test/second.yaml": "key2: two\nkey3: three",
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
}
|
assert doc["key"] == {"key1": "one", "key2": "two", "key3": "three"}
|
||||||
|
|
||||||
with patch_yaml_files(files):
|
|
||||||
conf = "key: !include_dir_merge_named /test"
|
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert doc["key"] == {"key1": "one", "key2": "two", "key3": "three"}
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.os.walk")
|
@patch("homeassistant.util.yaml.loader.os.walk")
|
||||||
def test_include_dir_merge_named_recursive(mock_walk, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/test/first.yaml": "key1: one",
|
||||||
|
"/test/tmp2/second.yaml": "key2: two",
|
||||||
|
"/test/tmp2/third.yaml": "key3: three\nkey4: four",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_include_dir_merge_named_recursive(
|
||||||
|
mock_walk, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test include dir merge named yaml."""
|
"""Test include dir merge named yaml."""
|
||||||
mock_walk.return_value = [
|
mock_walk.return_value = [
|
||||||
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
|
||||||
@ -270,27 +308,18 @@ def test_include_dir_merge_named_recursive(mock_walk, try_both_loaders):
|
|||||||
["/test/ignore", [], [".ignore.yaml"]],
|
["/test/ignore", [], [".ignore.yaml"]],
|
||||||
]
|
]
|
||||||
|
|
||||||
with patch_yaml_files(
|
conf = "key: !include_dir_merge_named /test"
|
||||||
{
|
with io.StringIO(conf) as file:
|
||||||
"/test/first.yaml": "key1: one",
|
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
|
||||||
"/test/tmp2/second.yaml": "key2: two",
|
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
||||||
"/test/tmp2/third.yaml": "key3: three\nkey4: four",
|
assert "tmp2" in mock_walk.return_value[0][1]
|
||||||
|
assert ".ignore" not in mock_walk.return_value[0][1]
|
||||||
|
assert doc["key"] == {
|
||||||
|
"key1": "one",
|
||||||
|
"key2": "two",
|
||||||
|
"key3": "three",
|
||||||
|
"key4": "four",
|
||||||
}
|
}
|
||||||
):
|
|
||||||
conf = "key: !include_dir_merge_named /test"
|
|
||||||
with io.StringIO(conf) as file:
|
|
||||||
assert (
|
|
||||||
".ignore" in mock_walk.return_value[0][1]
|
|
||||||
), "Expecting .ignore in here"
|
|
||||||
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
|
|
||||||
assert "tmp2" in mock_walk.return_value[0][1]
|
|
||||||
assert ".ignore" not in mock_walk.return_value[0][1]
|
|
||||||
assert doc["key"] == {
|
|
||||||
"key1": "one",
|
|
||||||
"key2": "two",
|
|
||||||
"key3": "three",
|
|
||||||
"key4": "four",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.util.yaml.loader.open", create=True)
|
@patch("homeassistant.util.yaml.loader.open", create=True)
|
||||||
@ -452,26 +481,31 @@ class TestSecrets(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_representing_yaml_loaded_data(try_both_dumpers):
|
@pytest.mark.parametrize("hass_config_yaml", ['key: [1, "2", 3]'])
|
||||||
|
def test_representing_yaml_loaded_data(
|
||||||
|
try_both_dumpers, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test we can represent YAML loaded data."""
|
"""Test we can represent YAML loaded data."""
|
||||||
files = {YAML_CONFIG_FILE: 'key: [1, "2", 3]'}
|
data = load_yaml_config_file(YAML_CONFIG_FILE)
|
||||||
with patch_yaml_files(files):
|
|
||||||
data = load_yaml_config_file(YAML_CONFIG_FILE)
|
|
||||||
assert yaml.dump(data) == "key:\n- 1\n- '2'\n- 3\n"
|
assert yaml.dump(data) == "key:\n- 1\n- '2'\n- 3\n"
|
||||||
|
|
||||||
|
|
||||||
def test_duplicate_key(caplog, try_both_loaders):
|
@pytest.mark.parametrize("hass_config_yaml", ["key: thing1\nkey: thing2"])
|
||||||
|
def test_duplicate_key(caplog, try_both_loaders, mock_hass_config_yaml: None) -> None:
|
||||||
"""Test duplicate dict keys."""
|
"""Test duplicate dict keys."""
|
||||||
files = {YAML_CONFIG_FILE: "key: thing1\nkey: thing2"}
|
load_yaml_config_file(YAML_CONFIG_FILE)
|
||||||
with patch_yaml_files(files):
|
|
||||||
load_yaml_config_file(YAML_CONFIG_FILE)
|
|
||||||
assert "contains duplicate key" in caplog.text
|
assert "contains duplicate key" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_no_recursive_secrets(caplog, try_both_loaders):
|
@pytest.mark.parametrize(
|
||||||
|
"hass_config_yaml_files",
|
||||||
|
[{YAML_CONFIG_FILE: "key: !secret a", yaml.SECRET_YAML: "a: 1\nb: !secret a"}],
|
||||||
|
)
|
||||||
|
def test_no_recursive_secrets(
|
||||||
|
caplog, try_both_loaders, mock_hass_config_yaml: None
|
||||||
|
) -> None:
|
||||||
"""Test that loading of secrets from the secrets file fails correctly."""
|
"""Test that loading of secrets from the secrets file fails correctly."""
|
||||||
files = {YAML_CONFIG_FILE: "key: !secret a", yaml.SECRET_YAML: "a: 1\nb: !secret a"}
|
with pytest.raises(HomeAssistantError) as e:
|
||||||
with patch_yaml_files(files), pytest.raises(HomeAssistantError) as e:
|
|
||||||
load_yaml_config_file(YAML_CONFIG_FILE)
|
load_yaml_config_file(YAML_CONFIG_FILE)
|
||||||
|
|
||||||
assert e.value.args == ("Secrets not supported in this YAML file",)
|
assert e.value.args == ("Secrets not supported in this YAML file",)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user