mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add media dirs core configuration (#40071)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
ce86112612
commit
5d518b5365
@ -15,4 +15,6 @@ MEDIA_CLASS_MAP = {
|
|||||||
"image": MEDIA_CLASS_IMAGE,
|
"image": MEDIA_CLASS_IMAGE,
|
||||||
}
|
}
|
||||||
URI_SCHEME = "media-source://"
|
URI_SCHEME = "media-source://"
|
||||||
URI_SCHEME_REGEX = re.compile(r"^media-source://(?P<domain>[^/]+)?(?P<identifier>.+)?")
|
URI_SCHEME_REGEX = re.compile(
|
||||||
|
r"^media-source:\/\/(?:(?P<domain>(?!.+__)(?!_)[\da-z_]+(?<!_))(?:\/(?P<identifier>(?!\/).+))?)?$"
|
||||||
|
)
|
||||||
|
@ -21,26 +21,7 @@ def async_setup(hass: HomeAssistant):
|
|||||||
"""Set up local media source."""
|
"""Set up local media source."""
|
||||||
source = LocalSource(hass)
|
source = LocalSource(hass)
|
||||||
hass.data[DOMAIN][DOMAIN] = source
|
hass.data[DOMAIN][DOMAIN] = source
|
||||||
hass.http.register_view(LocalMediaView(hass))
|
hass.http.register_view(LocalMediaView(hass, source))
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_parse_identifier(item: MediaSourceItem) -> Tuple[str, str]:
|
|
||||||
"""Parse identifier."""
|
|
||||||
if not item.identifier:
|
|
||||||
source_dir_id = "media"
|
|
||||||
location = ""
|
|
||||||
|
|
||||||
else:
|
|
||||||
source_dir_id, location = item.identifier.lstrip("/").split("/", 1)
|
|
||||||
|
|
||||||
if source_dir_id != "media":
|
|
||||||
raise Unresolvable("Unknown source directory.")
|
|
||||||
|
|
||||||
if location != sanitize_path(location):
|
|
||||||
raise Unresolvable("Invalid path.")
|
|
||||||
|
|
||||||
return source_dir_id, location
|
|
||||||
|
|
||||||
|
|
||||||
class LocalSource(MediaSource):
|
class LocalSource(MediaSource):
|
||||||
@ -56,22 +37,41 @@ class LocalSource(MediaSource):
|
|||||||
@callback
|
@callback
|
||||||
def async_full_path(self, source_dir_id, location) -> Path:
|
def async_full_path(self, source_dir_id, location) -> Path:
|
||||||
"""Return full path."""
|
"""Return full path."""
|
||||||
return self.hass.config.path("media", location)
|
return Path(self.hass.config.media_dirs[source_dir_id], location)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_parse_identifier(self, item: MediaSourceItem) -> Tuple[str, str]:
|
||||||
|
"""Parse identifier."""
|
||||||
|
if not item.identifier:
|
||||||
|
# Empty source_dir_id and location
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
source_dir_id, location = item.identifier.split("/", 1)
|
||||||
|
if source_dir_id not in self.hass.config.media_dirs:
|
||||||
|
raise Unresolvable("Unknown source directory.")
|
||||||
|
|
||||||
|
if location != sanitize_path(location):
|
||||||
|
raise Unresolvable("Invalid path.")
|
||||||
|
|
||||||
|
return source_dir_id, location
|
||||||
|
|
||||||
async def async_resolve_media(self, item: MediaSourceItem) -> str:
|
async def async_resolve_media(self, item: MediaSourceItem) -> str:
|
||||||
"""Resolve media to a url."""
|
"""Resolve media to a url."""
|
||||||
source_dir_id, location = async_parse_identifier(item)
|
source_dir_id, location = self.async_parse_identifier(item)
|
||||||
|
if source_dir_id == "" or source_dir_id not in self.hass.config.media_dirs:
|
||||||
|
raise Unresolvable("Unknown source directory.")
|
||||||
|
|
||||||
mime_type, _ = mimetypes.guess_type(
|
mime_type, _ = mimetypes.guess_type(
|
||||||
self.async_full_path(source_dir_id, location)
|
str(self.async_full_path(source_dir_id, location))
|
||||||
)
|
)
|
||||||
return PlayMedia(item.identifier, mime_type)
|
return PlayMedia(f"/local_source/{item.identifier}", mime_type)
|
||||||
|
|
||||||
async def async_browse_media(
|
async def async_browse_media(
|
||||||
self, item: MediaSourceItem, media_types: Tuple[str] = MEDIA_MIME_TYPES
|
self, item: MediaSourceItem, media_types: Tuple[str] = MEDIA_MIME_TYPES
|
||||||
) -> BrowseMediaSource:
|
) -> BrowseMediaSource:
|
||||||
"""Return media."""
|
"""Return media."""
|
||||||
try:
|
try:
|
||||||
source_dir_id, location = async_parse_identifier(item)
|
source_dir_id, location = self.async_parse_identifier(item)
|
||||||
except Unresolvable as err:
|
except Unresolvable as err:
|
||||||
raise BrowseError(str(err)) from err
|
raise BrowseError(str(err)) from err
|
||||||
|
|
||||||
@ -79,9 +79,37 @@ class LocalSource(MediaSource):
|
|||||||
self._browse_media, source_dir_id, location
|
self._browse_media, source_dir_id, location
|
||||||
)
|
)
|
||||||
|
|
||||||
def _browse_media(self, source_dir_id, location):
|
def _browse_media(self, source_dir_id: str, location: Path):
|
||||||
"""Browse media."""
|
"""Browse media."""
|
||||||
full_path = Path(self.hass.config.path("media", location))
|
|
||||||
|
# If only one media dir is configured, use that as the local media root
|
||||||
|
if source_dir_id == "" and len(self.hass.config.media_dirs) == 1:
|
||||||
|
source_dir_id = list(self.hass.config.media_dirs)[0]
|
||||||
|
|
||||||
|
# Multiple folder, root is requested
|
||||||
|
if source_dir_id == "":
|
||||||
|
if location:
|
||||||
|
raise BrowseError("Folder not found.")
|
||||||
|
|
||||||
|
base = BrowseMediaSource(
|
||||||
|
domain=DOMAIN,
|
||||||
|
identifier="",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
|
media_content_type=None,
|
||||||
|
title=self.name,
|
||||||
|
can_play=False,
|
||||||
|
can_expand=True,
|
||||||
|
children_media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
|
)
|
||||||
|
|
||||||
|
base.children = [
|
||||||
|
self._browse_media(source_dir_id, "")
|
||||||
|
for source_dir_id in self.hass.config.media_dirs
|
||||||
|
]
|
||||||
|
|
||||||
|
return base
|
||||||
|
|
||||||
|
full_path = Path(self.hass.config.media_dirs[source_dir_id], location)
|
||||||
|
|
||||||
if not full_path.exists():
|
if not full_path.exists():
|
||||||
if location == "":
|
if location == "":
|
||||||
@ -118,7 +146,7 @@ class LocalSource(MediaSource):
|
|||||||
|
|
||||||
media = BrowseMediaSource(
|
media = BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=f"{source_dir_id}/{path.relative_to(self.hass.config.path('media'))}",
|
identifier=f"{source_dir_id}/{path.relative_to(self.hass.config.media_dirs[source_dir_id])}",
|
||||||
media_class=media_class,
|
media_class=media_class,
|
||||||
media_content_type=mime_type or "",
|
media_content_type=mime_type or "",
|
||||||
title=title,
|
title=title,
|
||||||
@ -149,19 +177,25 @@ class LocalMediaView(HomeAssistantView):
|
|||||||
Returns media files in config/media.
|
Returns media files in config/media.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url = "/media/{location:.*}"
|
url = "/local_source/{source_dir_id}/{location:.*}"
|
||||||
name = "media"
|
name = "media"
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant):
|
def __init__(self, hass: HomeAssistant, source: LocalSource):
|
||||||
"""Initialize the media view."""
|
"""Initialize the media view."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
self.source = source
|
||||||
|
|
||||||
async def get(self, request: web.Request, location: str) -> web.FileResponse:
|
async def get(
|
||||||
|
self, request: web.Request, source_dir_id: str, location: str
|
||||||
|
) -> web.FileResponse:
|
||||||
"""Start a GET request."""
|
"""Start a GET request."""
|
||||||
if location != sanitize_path(location):
|
if location != sanitize_path(location):
|
||||||
return web.HTTPNotFound()
|
return web.HTTPNotFound()
|
||||||
|
|
||||||
media_path = Path(self.hass.config.path("media", location))
|
if source_dir_id not in self.hass.config.media_dirs:
|
||||||
|
return web.HTTPNotFound()
|
||||||
|
|
||||||
|
media_path = self.source.async_full_path(source_dir_id, location)
|
||||||
|
|
||||||
# Check that the file exists
|
# Check that the file exists
|
||||||
if not media_path.is_file():
|
if not media_path.is_file():
|
||||||
|
@ -33,6 +33,7 @@ from homeassistant.const import (
|
|||||||
CONF_INTERNAL_URL,
|
CONF_INTERNAL_URL,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
CONF_LONGITUDE,
|
CONF_LONGITUDE,
|
||||||
|
CONF_MEDIA_DIRS,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PACKAGES,
|
CONF_PACKAGES,
|
||||||
CONF_TEMPERATURE_UNIT,
|
CONF_TEMPERATURE_UNIT,
|
||||||
@ -221,6 +222,8 @@ CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend(
|
|||||||
],
|
],
|
||||||
_no_duplicate_auth_mfa_module,
|
_no_duplicate_auth_mfa_module,
|
||||||
),
|
),
|
||||||
|
# pylint: disable=no-value-for-parameter
|
||||||
|
vol.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(vol.IsDir()),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -485,6 +488,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: Dict) -> Non
|
|||||||
CONF_UNIT_SYSTEM,
|
CONF_UNIT_SYSTEM,
|
||||||
CONF_EXTERNAL_URL,
|
CONF_EXTERNAL_URL,
|
||||||
CONF_INTERNAL_URL,
|
CONF_INTERNAL_URL,
|
||||||
|
CONF_MEDIA_DIRS,
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
hac.config_source = SOURCE_YAML
|
hac.config_source = SOURCE_YAML
|
||||||
@ -496,6 +500,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: Dict) -> Non
|
|||||||
(CONF_ELEVATION, "elevation"),
|
(CONF_ELEVATION, "elevation"),
|
||||||
(CONF_INTERNAL_URL, "internal_url"),
|
(CONF_INTERNAL_URL, "internal_url"),
|
||||||
(CONF_EXTERNAL_URL, "external_url"),
|
(CONF_EXTERNAL_URL, "external_url"),
|
||||||
|
(CONF_MEDIA_DIRS, "media_dirs"),
|
||||||
):
|
):
|
||||||
if key in config:
|
if key in config:
|
||||||
setattr(hac, attr, config[key])
|
setattr(hac, attr, config[key])
|
||||||
@ -503,8 +508,14 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: Dict) -> Non
|
|||||||
if CONF_TIME_ZONE in config:
|
if CONF_TIME_ZONE in config:
|
||||||
hac.set_time_zone(config[CONF_TIME_ZONE])
|
hac.set_time_zone(config[CONF_TIME_ZONE])
|
||||||
|
|
||||||
|
if CONF_MEDIA_DIRS not in config:
|
||||||
|
if is_docker_env():
|
||||||
|
hac.media_dirs = {"media": "/media"}
|
||||||
|
else:
|
||||||
|
hac.media_dirs = {"media": hass.config.path("media")}
|
||||||
|
|
||||||
# Init whitelist external dir
|
# Init whitelist external dir
|
||||||
hac.allowlist_external_dirs = {hass.config.path("www"), hass.config.path("media")}
|
hac.allowlist_external_dirs = {hass.config.path("www"), *hac.media_dirs.values()}
|
||||||
if CONF_ALLOWLIST_EXTERNAL_DIRS in config:
|
if CONF_ALLOWLIST_EXTERNAL_DIRS in config:
|
||||||
hac.allowlist_external_dirs.update(set(config[CONF_ALLOWLIST_EXTERNAL_DIRS]))
|
hac.allowlist_external_dirs.update(set(config[CONF_ALLOWLIST_EXTERNAL_DIRS]))
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@ CONF_LIGHTS = "lights"
|
|||||||
CONF_LONGITUDE = "longitude"
|
CONF_LONGITUDE = "longitude"
|
||||||
CONF_MAC = "mac"
|
CONF_MAC = "mac"
|
||||||
CONF_MAXIMUM = "maximum"
|
CONF_MAXIMUM = "maximum"
|
||||||
|
CONF_MEDIA_DIRS = "media_dirs"
|
||||||
CONF_METHOD = "method"
|
CONF_METHOD = "method"
|
||||||
CONF_MINIMUM = "minimum"
|
CONF_MINIMUM = "minimum"
|
||||||
CONF_MODE = "mode"
|
CONF_MODE = "mode"
|
||||||
|
@ -1390,6 +1390,9 @@ class Config:
|
|||||||
# List of allowed external URLs that integrations may use
|
# List of allowed external URLs that integrations may use
|
||||||
self.allowlist_external_urls: Set[str] = set()
|
self.allowlist_external_urls: Set[str] = set()
|
||||||
|
|
||||||
|
# Dictionary of Media folders that integrations may use
|
||||||
|
self.media_dirs: Dict[str, str] = {}
|
||||||
|
|
||||||
# If Home Assistant is running in safe mode
|
# If Home Assistant is running in safe mode
|
||||||
self.safe_mode: bool = False
|
self.safe_mode: bool = False
|
||||||
|
|
||||||
|
@ -205,6 +205,7 @@ async def async_test_home_assistant(loop):
|
|||||||
hass.config.elevation = 0
|
hass.config.elevation = 0
|
||||||
hass.config.time_zone = date_util.get_time_zone("US/Pacific")
|
hass.config.time_zone = date_util.get_time_zone("US/Pacific")
|
||||||
hass.config.units = METRIC_SYSTEM
|
hass.config.units = METRIC_SYSTEM
|
||||||
|
hass.config.media_dirs = {"media": get_test_config_dir("media")}
|
||||||
hass.config.skip_pip = True
|
hass.config.skip_pip = True
|
||||||
|
|
||||||
hass.config_entries = config_entries.ConfigEntries(hass, {})
|
hass.config_entries = config_entries.ConfigEntries(hass, {})
|
||||||
|
@ -5,6 +5,7 @@ from homeassistant.components import media_source
|
|||||||
from homeassistant.components.media_player.const import MEDIA_CLASS_DIRECTORY
|
from homeassistant.components.media_player.const import MEDIA_CLASS_DIRECTORY
|
||||||
from homeassistant.components.media_player.errors import BrowseError
|
from homeassistant.components.media_player.errors import BrowseError
|
||||||
from homeassistant.components.media_source import const
|
from homeassistant.components.media_source import const
|
||||||
|
from homeassistant.components.media_source.error import Unresolvable
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import patch
|
||||||
@ -62,11 +63,23 @@ async def test_async_resolve_media(hass):
|
|||||||
assert await async_setup_component(hass, const.DOMAIN, {})
|
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Test no media content
|
media = await media_source.async_resolve_media(
|
||||||
media = await media_source.async_resolve_media(hass, "")
|
hass,
|
||||||
|
media_source.generate_media_source_id(const.DOMAIN, "media/test.mp3"),
|
||||||
|
)
|
||||||
assert isinstance(media, media_source.models.PlayMedia)
|
assert isinstance(media, media_source.models.PlayMedia)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_unresolve_media(hass):
|
||||||
|
"""Test browse media."""
|
||||||
|
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Test no media content
|
||||||
|
with pytest.raises(Unresolvable):
|
||||||
|
await media_source.async_resolve_media(hass, "")
|
||||||
|
|
||||||
|
|
||||||
async def test_websocket_browse_media(hass, hass_ws_client):
|
async def test_websocket_browse_media(hass, hass_ws_client):
|
||||||
"""Test browse media websocket."""
|
"""Test browse media websocket."""
|
||||||
assert await async_setup_component(hass, const.DOMAIN, {})
|
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||||
@ -127,7 +140,7 @@ async def test_websocket_resolve_media(hass, hass_ws_client):
|
|||||||
|
|
||||||
client = await hass_ws_client(hass)
|
client = await hass_ws_client(hass)
|
||||||
|
|
||||||
media = media_source.models.PlayMedia("/media/test.mp3", "audio/mpeg")
|
media = media_source.models.PlayMedia("/local_source/media/test.mp3", "audio/mpeg")
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.media_source.async_resolve_media",
|
"homeassistant.components.media_source.async_resolve_media",
|
||||||
|
@ -3,11 +3,18 @@ import pytest
|
|||||||
|
|
||||||
from homeassistant.components import media_source
|
from homeassistant.components import media_source
|
||||||
from homeassistant.components.media_source import const
|
from homeassistant.components.media_source import const
|
||||||
|
from homeassistant.config import async_process_ha_core_config
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
|
||||||
async def test_async_browse_media(hass):
|
async def test_async_browse_media(hass):
|
||||||
"""Test browse media."""
|
"""Test browse media."""
|
||||||
|
local_media = hass.config.path("media")
|
||||||
|
await async_process_ha_core_config(
|
||||||
|
hass, {"media_dirs": {"media": local_media, "recordings": local_media}}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert await async_setup_component(hass, const.DOMAIN, {})
|
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -40,27 +47,53 @@ async def test_async_browse_media(hass):
|
|||||||
assert str(excinfo.value) == "Invalid path."
|
assert str(excinfo.value) == "Invalid path."
|
||||||
|
|
||||||
# Test successful listing
|
# Test successful listing
|
||||||
|
media = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{const.DOMAIN}"
|
||||||
|
)
|
||||||
|
assert media
|
||||||
|
|
||||||
media = await media_source.async_browse_media(
|
media = await media_source.async_browse_media(
|
||||||
hass, f"{const.URI_SCHEME}{const.DOMAIN}/media/."
|
hass, f"{const.URI_SCHEME}{const.DOMAIN}/media/."
|
||||||
)
|
)
|
||||||
assert media
|
assert media
|
||||||
|
|
||||||
|
media = await media_source.async_browse_media(
|
||||||
|
hass, f"{const.URI_SCHEME}{const.DOMAIN}/recordings/."
|
||||||
|
)
|
||||||
|
assert media
|
||||||
|
|
||||||
|
|
||||||
async def test_media_view(hass, hass_client):
|
async def test_media_view(hass, hass_client):
|
||||||
"""Test media view."""
|
"""Test media view."""
|
||||||
|
local_media = hass.config.path("media")
|
||||||
|
await async_process_ha_core_config(
|
||||||
|
hass, {"media_dirs": {"media": local_media, "recordings": local_media}}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert await async_setup_component(hass, const.DOMAIN, {})
|
assert await async_setup_component(hass, const.DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
client = await hass_client()
|
client = await hass_client()
|
||||||
|
|
||||||
# Protects against non-existent files
|
# Protects against non-existent files
|
||||||
resp = await client.get("/media/invalid.txt")
|
resp = await client.get("/local_source/media/invalid.txt")
|
||||||
|
assert resp.status == 404
|
||||||
|
|
||||||
|
resp = await client.get("/local_source/recordings/invalid.txt")
|
||||||
assert resp.status == 404
|
assert resp.status == 404
|
||||||
|
|
||||||
# Protects against non-media files
|
# Protects against non-media files
|
||||||
resp = await client.get("/media/not_media.txt")
|
resp = await client.get("/local_source/media/not_media.txt")
|
||||||
|
assert resp.status == 404
|
||||||
|
|
||||||
|
# Protects against unknown local media sources
|
||||||
|
resp = await client.get("/local_source/unknown_source/not_media.txt")
|
||||||
assert resp.status == 404
|
assert resp.status == 404
|
||||||
|
|
||||||
# Fetch available media
|
# Fetch available media
|
||||||
resp = await client.get("/media/test.mp3")
|
resp = await client.get("/local_source/media/test.mp3")
|
||||||
|
assert resp.status == 200
|
||||||
|
|
||||||
|
resp = await client.get("/local_source/recordings/test.mp3")
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
|
@ -440,6 +440,7 @@ async def test_loading_configuration(hass):
|
|||||||
"allowlist_external_dirs": "/etc",
|
"allowlist_external_dirs": "/etc",
|
||||||
"external_url": "https://www.example.com",
|
"external_url": "https://www.example.com",
|
||||||
"internal_url": "http://example.local",
|
"internal_url": "http://example.local",
|
||||||
|
"media_dirs": {"mymedia": "/usr"},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -453,6 +454,8 @@ async def test_loading_configuration(hass):
|
|||||||
assert hass.config.internal_url == "http://example.local"
|
assert hass.config.internal_url == "http://example.local"
|
||||||
assert len(hass.config.allowlist_external_dirs) == 3
|
assert len(hass.config.allowlist_external_dirs) == 3
|
||||||
assert "/etc" in hass.config.allowlist_external_dirs
|
assert "/etc" in hass.config.allowlist_external_dirs
|
||||||
|
assert "/usr" in hass.config.allowlist_external_dirs
|
||||||
|
assert hass.config.media_dirs == {"mymedia": "/usr"}
|
||||||
assert hass.config.config_source == config_util.SOURCE_YAML
|
assert hass.config.config_source == config_util.SOURCE_YAML
|
||||||
|
|
||||||
|
|
||||||
@ -483,6 +486,22 @@ async def test_loading_configuration_temperature_unit(hass):
|
|||||||
assert hass.config.config_source == config_util.SOURCE_YAML
|
assert hass.config.config_source == config_util.SOURCE_YAML
|
||||||
|
|
||||||
|
|
||||||
|
async def test_loading_configuration_default_media_dirs_docker(hass):
|
||||||
|
"""Test loading core config onto hass object."""
|
||||||
|
with patch("homeassistant.config.is_docker_env", return_value=True):
|
||||||
|
await config_util.async_process_ha_core_config(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
"name": "Huis",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert hass.config.location_name == "Huis"
|
||||||
|
assert len(hass.config.allowlist_external_dirs) == 2
|
||||||
|
assert "/media" in hass.config.allowlist_external_dirs
|
||||||
|
assert hass.config.media_dirs == {"media": "/media"}
|
||||||
|
|
||||||
|
|
||||||
async def test_loading_configuration_from_packages(hass):
|
async def test_loading_configuration_from_packages(hass):
|
||||||
"""Test loading packages config onto hass object config."""
|
"""Test loading packages config onto hass object config."""
|
||||||
await config_util.async_process_ha_core_config(
|
await config_util.async_process_ha_core_config(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user