diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py index 7019dbe60b2..b6bfd2122ba 100644 --- a/homeassistant/components/stream/__init__.py +++ b/homeassistant/components/stream/__init__.py @@ -97,19 +97,21 @@ def create_stream( return stream +DOMAIN_SCHEMA = vol.Schema( + { + vol.Optional(CONF_LL_HLS, default=True): cv.boolean, + vol.Optional(CONF_SEGMENT_DURATION, default=6): vol.All( + cv.positive_float, vol.Range(min=2, max=10) + ), + vol.Optional(CONF_PART_DURATION, default=1): vol.All( + cv.positive_float, vol.Range(min=0.2, max=1.5) + ), + } +) + CONFIG_SCHEMA = vol.Schema( { - DOMAIN: vol.Schema( - { - vol.Optional(CONF_LL_HLS, default=False): cv.boolean, - vol.Optional(CONF_SEGMENT_DURATION, default=6): vol.All( - cv.positive_float, vol.Range(min=2, max=10) - ), - vol.Optional(CONF_PART_DURATION, default=1): vol.All( - cv.positive_float, vol.Range(min=0.2, max=1.5) - ), - } - ) + DOMAIN: DOMAIN_SCHEMA, }, extra=vol.ALLOW_EXTRA, ) @@ -154,7 +156,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass.data[DOMAIN] = {} hass.data[DOMAIN][ATTR_ENDPOINTS] = {} hass.data[DOMAIN][ATTR_STREAMS] = [] - if (conf := config.get(DOMAIN)) and conf[CONF_LL_HLS]: + conf = DOMAIN_SCHEMA(config.get(DOMAIN, {})) + if conf[CONF_LL_HLS]: assert isinstance(conf[CONF_SEGMENT_DURATION], float) assert isinstance(conf[CONF_PART_DURATION], float) hass.data[DOMAIN][ATTR_SETTINGS] = StreamSettings( diff --git a/tests/components/stream/test_hls.py b/tests/components/stream/test_hls.py index 34c87349811..0492fec14f0 100644 --- a/tests/components/stream/test_hls.py +++ b/tests/components/stream/test_hls.py @@ -29,6 +29,18 @@ SEGMENT_DURATION = 10 TEST_TIMEOUT = 5.0 # Lower than 9s home assistant timeout MAX_ABORT_SEGMENTS = 20 # Abort test to avoid looping forever +HLS_CONFIG = { + "stream": { + "ll_hls": False, + } +} + + +@pytest.fixture +async def setup_component(hass) -> None: + """Test fixture to setup the stream component.""" + await async_setup_component(hass, "stream", HLS_CONFIG) + class HlsClient: """Test fixture for fetching the hls stream.""" @@ -114,14 +126,15 @@ def make_playlist( return "\n".join(response) -async def test_hls_stream(hass, hls_stream, stream_worker_sync, h264_video): +async def test_hls_stream( + hass, setup_component, hls_stream, stream_worker_sync, h264_video +): """ Test hls stream. Purposefully not mocking anything here to test full integration with the stream component. """ - await async_setup_component(hass, "stream", {"stream": {}}) stream_worker_sync.pause() @@ -164,10 +177,10 @@ async def test_hls_stream(hass, hls_stream, stream_worker_sync, h264_video): assert fail_response.status == HTTPStatus.NOT_FOUND -async def test_stream_timeout(hass, hass_client, stream_worker_sync, h264_video): +async def test_stream_timeout( + hass, hass_client, setup_component, stream_worker_sync, h264_video +): """Test hls stream timeout.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream_worker_sync.pause() # Setup demo HLS track @@ -217,11 +230,9 @@ async def test_stream_timeout(hass, hass_client, stream_worker_sync, h264_video) async def test_stream_timeout_after_stop( - hass, hass_client, stream_worker_sync, h264_video + hass, hass_client, setup_component, stream_worker_sync, h264_video ): """Test hls stream timeout after the stream has been stopped already.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream_worker_sync.pause() # Setup demo HLS track @@ -241,10 +252,8 @@ async def test_stream_timeout_after_stop( await hass.async_block_till_done() -async def test_stream_keepalive(hass): +async def test_stream_keepalive(hass, setup_component): """Test hls stream retries the stream when keepalive=True.""" - await async_setup_component(hass, "stream", {"stream": {}}) - # Setup demo HLS track source = "test_stream_keepalive_source" stream = create_stream(hass, source, {}) @@ -291,10 +300,8 @@ async def test_stream_keepalive(hass): assert available_states == [True, False, True] -async def test_hls_playlist_view_no_output(hass, hls_stream): +async def test_hls_playlist_view_no_output(hass, setup_component, hls_stream): """Test rendering the hls playlist with no output segments.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream = create_stream(hass, STREAM_SOURCE, {}) stream.add_provider(HLS_PROVIDER) @@ -305,10 +312,8 @@ async def test_hls_playlist_view_no_output(hass, hls_stream): assert resp.status == HTTPStatus.NOT_FOUND -async def test_hls_playlist_view(hass, hls_stream, stream_worker_sync): +async def test_hls_playlist_view(hass, setup_component, hls_stream, stream_worker_sync): """Test rendering the hls playlist with 1 and 2 output segments.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream = create_stream(hass, STREAM_SOURCE, {}) stream_worker_sync.pause() hls = stream.add_provider(HLS_PROVIDER) @@ -338,10 +343,8 @@ async def test_hls_playlist_view(hass, hls_stream, stream_worker_sync): stream.stop() -async def test_hls_max_segments(hass, hls_stream, stream_worker_sync): +async def test_hls_max_segments(hass, setup_component, hls_stream, stream_worker_sync): """Test rendering the hls playlist with more segments than the segment deque can hold.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream = create_stream(hass, STREAM_SOURCE, {}) stream_worker_sync.pause() hls = stream.add_provider(HLS_PROVIDER) @@ -389,9 +392,10 @@ async def test_hls_max_segments(hass, hls_stream, stream_worker_sync): stream.stop() -async def test_hls_playlist_view_discontinuity(hass, hls_stream, stream_worker_sync): +async def test_hls_playlist_view_discontinuity( + hass, setup_component, hls_stream, stream_worker_sync +): """Test a discontinuity across segments in the stream with 3 segments.""" - await async_setup_component(hass, "stream", {"stream": {}}) stream = create_stream(hass, STREAM_SOURCE, {}) stream_worker_sync.pause() @@ -426,10 +430,10 @@ async def test_hls_playlist_view_discontinuity(hass, hls_stream, stream_worker_s stream.stop() -async def test_hls_max_segments_discontinuity(hass, hls_stream, stream_worker_sync): +async def test_hls_max_segments_discontinuity( + hass, setup_component, hls_stream, stream_worker_sync +): """Test a discontinuity with more segments than the segment deque can hold.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream = create_stream(hass, STREAM_SOURCE, {}) stream_worker_sync.pause() hls = stream.add_provider(HLS_PROVIDER) @@ -469,10 +473,10 @@ async def test_hls_max_segments_discontinuity(hass, hls_stream, stream_worker_sy stream.stop() -async def test_remove_incomplete_segment_on_exit(hass, stream_worker_sync): +async def test_remove_incomplete_segment_on_exit( + hass, setup_component, stream_worker_sync +): """Test that the incomplete segment gets removed when the worker thread quits.""" - await async_setup_component(hass, "stream", {"stream": {}}) - stream = create_stream(hass, STREAM_SOURCE, {}) stream_worker_sync.pause() stream.start()