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:
Jan Bouwhuis 2023-02-20 16:57:12 +01:00 committed by GitHub
parent 1759f58fc1
commit 4f6a25b470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 498 additions and 383 deletions

View File

@ -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",

View File

@ -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

View File

@ -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"}, }
}

View File

@ -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,

View File

@ -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"] == {}

View File

@ -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()

View File

@ -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

View File

@ -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",)