Move core config class to core_config.py (#129163)
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
"""Test core_config."""
|
||||
|
||||
import asyncio
|
||||
from collections import OrderedDict
|
||||
import copy
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock, PropertyMock, patch
|
||||
|
||||
import pytest
|
||||
from voluptuous import Invalid, MultipleInvalid
|
||||
@@ -18,12 +23,18 @@ from homeassistant.const import (
|
||||
CONF_LATITUDE,
|
||||
CONF_LONGITUDE,
|
||||
CONF_NAME,
|
||||
CONF_UNIT_SYSTEM,
|
||||
EVENT_CORE_CONFIG_UPDATE,
|
||||
__version__,
|
||||
)
|
||||
from homeassistant.core import ConfigSource, HomeAssistant, State
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.core_config import (
|
||||
_CUSTOMIZE_DICT_SCHEMA,
|
||||
CORE_CONFIG_SCHEMA,
|
||||
CORE_STORAGE_KEY,
|
||||
DATA_CUSTOMIZE,
|
||||
Config,
|
||||
ConfigSource,
|
||||
_validate_stun_or_turn_url,
|
||||
async_process_ha_core_config,
|
||||
)
|
||||
@@ -35,7 +46,7 @@ from homeassistant.util.unit_system import (
|
||||
UnitSystem,
|
||||
)
|
||||
|
||||
from .common import MockUser
|
||||
from .common import MockUser, async_capture_events
|
||||
|
||||
|
||||
def test_core_config_schema() -> None:
|
||||
@@ -821,3 +832,252 @@ async def test_configuration_legacy_template_is_removed(hass: HomeAssistant) ->
|
||||
)
|
||||
|
||||
assert not getattr(hass.config, "legacy_templates")
|
||||
|
||||
|
||||
async def test_config_defaults() -> None:
|
||||
"""Test config defaults."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
assert config.hass is hass
|
||||
assert config.latitude == 0
|
||||
assert config.longitude == 0
|
||||
assert config.elevation == 0
|
||||
assert config.location_name == "Home"
|
||||
assert config.time_zone == "UTC"
|
||||
assert config.internal_url is None
|
||||
assert config.external_url is None
|
||||
assert config.config_source is ConfigSource.DEFAULT
|
||||
assert config.skip_pip is False
|
||||
assert config.skip_pip_packages == []
|
||||
assert config.components == set()
|
||||
assert config.api is None
|
||||
assert config.config_dir == "/test/ha-config"
|
||||
assert config.allowlist_external_dirs == set()
|
||||
assert config.allowlist_external_urls == set()
|
||||
assert config.media_dirs == {}
|
||||
assert config.recovery_mode is False
|
||||
assert config.legacy_templates is False
|
||||
assert config.currency == "EUR"
|
||||
assert config.country is None
|
||||
assert config.language == "en"
|
||||
assert config.radius == 100
|
||||
|
||||
|
||||
async def test_config_path_with_file() -> None:
|
||||
"""Test get_config_path method."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
assert config.path("test.conf") == "/test/ha-config/test.conf"
|
||||
|
||||
|
||||
async def test_config_path_with_dir_and_file() -> None:
|
||||
"""Test get_config_path method."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
assert config.path("dir", "test.conf") == "/test/ha-config/dir/test.conf"
|
||||
|
||||
|
||||
async def test_config_as_dict() -> None:
|
||||
"""Test as dict."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
type(config.hass.state).value = PropertyMock(return_value="RUNNING")
|
||||
expected = {
|
||||
"latitude": 0,
|
||||
"longitude": 0,
|
||||
"elevation": 0,
|
||||
CONF_UNIT_SYSTEM: METRIC_SYSTEM.as_dict(),
|
||||
"location_name": "Home",
|
||||
"time_zone": "UTC",
|
||||
"components": [],
|
||||
"config_dir": "/test/ha-config",
|
||||
"whitelist_external_dirs": [],
|
||||
"allowlist_external_dirs": [],
|
||||
"allowlist_external_urls": [],
|
||||
"version": __version__,
|
||||
"config_source": ConfigSource.DEFAULT,
|
||||
"recovery_mode": False,
|
||||
"state": "RUNNING",
|
||||
"external_url": None,
|
||||
"internal_url": None,
|
||||
"currency": "EUR",
|
||||
"country": None,
|
||||
"language": "en",
|
||||
"safe_mode": False,
|
||||
"debug": False,
|
||||
"radius": 100,
|
||||
}
|
||||
|
||||
assert expected == config.as_dict()
|
||||
|
||||
|
||||
async def test_config_is_allowed_path() -> None:
|
||||
"""Test is_allowed_path method."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
with TemporaryDirectory() as tmp_dir:
|
||||
# The created dir is in /tmp. This is a symlink on OS X
|
||||
# causing this test to fail unless we resolve path first.
|
||||
config.allowlist_external_dirs = {os.path.realpath(tmp_dir)}
|
||||
|
||||
test_file = os.path.join(tmp_dir, "test.jpg")
|
||||
await asyncio.get_running_loop().run_in_executor(
|
||||
None, Path(test_file).write_text, "test"
|
||||
)
|
||||
|
||||
valid = [test_file, tmp_dir, os.path.join(tmp_dir, "notfound321")]
|
||||
for path in valid:
|
||||
assert config.is_allowed_path(path)
|
||||
|
||||
config.allowlist_external_dirs = {"/home", "/var"}
|
||||
|
||||
invalid = [
|
||||
"/hass/config/secure",
|
||||
"/etc/passwd",
|
||||
"/root/secure_file",
|
||||
"/var/../etc/passwd",
|
||||
test_file,
|
||||
]
|
||||
for path in invalid:
|
||||
assert not config.is_allowed_path(path)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
config.is_allowed_path(None)
|
||||
|
||||
|
||||
async def test_config_is_allowed_external_url() -> None:
|
||||
"""Test is_allowed_external_url method."""
|
||||
hass = Mock()
|
||||
hass.data = {}
|
||||
config = Config(hass, "/test/ha-config")
|
||||
config.allowlist_external_urls = [
|
||||
"http://x.com/",
|
||||
"https://y.com/bla/",
|
||||
"https://z.com/images/1.jpg/",
|
||||
]
|
||||
|
||||
valid = [
|
||||
"http://x.com/1.jpg",
|
||||
"http://x.com",
|
||||
"https://y.com/bla/",
|
||||
"https://y.com/bla/2.png",
|
||||
"https://z.com/images/1.jpg",
|
||||
]
|
||||
for url in valid:
|
||||
assert config.is_allowed_external_url(url)
|
||||
|
||||
invalid = [
|
||||
"https://a.co",
|
||||
"https://y.com/bla_wrong",
|
||||
"https://y.com/bla/../image.jpg",
|
||||
"https://z.com/images",
|
||||
]
|
||||
for url in invalid:
|
||||
assert not config.is_allowed_external_url(url)
|
||||
|
||||
|
||||
async def test_event_on_update(hass: HomeAssistant) -> None:
|
||||
"""Test that event is fired on update."""
|
||||
events = async_capture_events(hass, EVENT_CORE_CONFIG_UPDATE)
|
||||
|
||||
assert hass.config.latitude != 12
|
||||
|
||||
await hass.config.async_update(latitude=12)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.config.latitude == 12
|
||||
assert len(events) == 1
|
||||
assert events[0].data == {"latitude": 12}
|
||||
|
||||
|
||||
async def test_bad_timezone_raises_value_error(hass: HomeAssistant) -> None:
|
||||
"""Test bad timezone raises ValueError."""
|
||||
with pytest.raises(ValueError):
|
||||
await hass.config.async_update(time_zone="not_a_timezone")
|
||||
|
||||
|
||||
async def test_additional_data_in_core_config(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test that we can handle additional data in core configuration."""
|
||||
config = Config(hass, "/test/ha-config")
|
||||
config.async_initialize()
|
||||
hass_storage[CORE_STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"data": {"location_name": "Test Name", "additional_valid_key": "value"},
|
||||
}
|
||||
await config.async_load()
|
||||
assert config.location_name == "Test Name"
|
||||
|
||||
|
||||
async def test_incorrect_internal_external_url(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test that we warn when detecting invalid internal/external url."""
|
||||
config = Config(hass, "/test/ha-config")
|
||||
config.async_initialize()
|
||||
|
||||
hass_storage[CORE_STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"data": {
|
||||
"internal_url": None,
|
||||
"external_url": None,
|
||||
},
|
||||
}
|
||||
await config.async_load()
|
||||
assert "Invalid external_url set" not in caplog.text
|
||||
assert "Invalid internal_url set" not in caplog.text
|
||||
|
||||
config = Config(hass, "/test/ha-config")
|
||||
config.async_initialize()
|
||||
|
||||
hass_storage[CORE_STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"data": {
|
||||
"internal_url": "https://community.home-assistant.io/profile",
|
||||
"external_url": "https://www.home-assistant.io/blue",
|
||||
},
|
||||
}
|
||||
await config.async_load()
|
||||
assert "Invalid external_url set" in caplog.text
|
||||
assert "Invalid internal_url set" in caplog.text
|
||||
|
||||
|
||||
async def test_top_level_components(hass: HomeAssistant) -> None:
|
||||
"""Test top level components are updated when components change."""
|
||||
hass.config.components.add("homeassistant")
|
||||
assert hass.config.components == {"homeassistant"}
|
||||
assert hass.config.top_level_components == {"homeassistant"}
|
||||
hass.config.components.add("homeassistant.scene")
|
||||
assert hass.config.components == {"homeassistant", "homeassistant.scene"}
|
||||
assert hass.config.top_level_components == {"homeassistant"}
|
||||
hass.config.components.remove("homeassistant")
|
||||
assert hass.config.components == {"homeassistant.scene"}
|
||||
assert hass.config.top_level_components == set()
|
||||
with pytest.raises(ValueError):
|
||||
hass.config.components.remove("homeassistant.scene")
|
||||
with pytest.raises(NotImplementedError):
|
||||
hass.config.components.discard("homeassistant")
|
||||
|
||||
|
||||
async def test_debug_mode_defaults_to_off(hass: HomeAssistant) -> None:
|
||||
"""Test debug mode defaults to off."""
|
||||
assert not hass.config.debug
|
||||
|
||||
|
||||
async def test_set_time_zone_deprecated(hass: HomeAssistant) -> None:
|
||||
"""Test set_time_zone is deprecated."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match=re.escape(
|
||||
"Detected code that set the time zone using set_time_zone instead of "
|
||||
"async_set_time_zone which will stop working in Home Assistant 2025.6. "
|
||||
"Please report this issue.",
|
||||
),
|
||||
):
|
||||
await hass.config.set_time_zone("America/New_York")
|
||||
|
||||
Reference in New Issue
Block a user