mirror of
https://github.com/home-assistant/core.git
synced 2026-09-27 01:46:11 -04:00
Split StreamState class out of SegmentBuffer (#60423)
This refactoring was pulled out of https://github.com/home-assistant/core/pull/53676 as an initial step towards reverting the addition of the SegmentBuffer class, which will be unrolled back into a for loop. The StreamState class holds the persistent state in stream that is used across stream worker instantiations, e.g. state across a retry or url expiration, which primarily handles discontinuities. By itself, this PR is not a large win until follow up PRs further simplify the SegmentBuffer class.
This commit is contained in:
@@ -23,7 +23,7 @@ import async_timeout
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.stream.core import Segment, StreamOutput
|
||||
from homeassistant.components.stream.worker import SegmentBuffer
|
||||
from homeassistant.components.stream.worker import StreamState
|
||||
|
||||
TEST_TIMEOUT = 7.0 # Lower than 9s home assistant timeout
|
||||
|
||||
@@ -34,7 +34,7 @@ class WorkerSync:
|
||||
def __init__(self):
|
||||
"""Initialize WorkerSync."""
|
||||
self._event = None
|
||||
self._original = SegmentBuffer.discontinuity
|
||||
self._original = StreamState.discontinuity
|
||||
|
||||
def pause(self):
|
||||
"""Pause the worker before it finalizes the stream."""
|
||||
@@ -45,7 +45,7 @@ class WorkerSync:
|
||||
logging.debug("waking blocked worker")
|
||||
self._event.set()
|
||||
|
||||
def blocking_discontinuity(self, stream: SegmentBuffer):
|
||||
def blocking_discontinuity(self, stream_state: StreamState):
|
||||
"""Intercept call to pause stream worker."""
|
||||
# Worker is ending the stream, which clears all output buffers.
|
||||
# Block the worker thread until the test has a chance to verify
|
||||
@@ -55,7 +55,7 @@ class WorkerSync:
|
||||
self._event.wait()
|
||||
|
||||
# Forward to actual implementation
|
||||
self._original(stream)
|
||||
self._original(stream_state)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@@ -63,7 +63,7 @@ def stream_worker_sync(hass):
|
||||
"""Patch StreamOutput to allow test to synchronize worker stream end."""
|
||||
sync = WorkerSync()
|
||||
with patch(
|
||||
"homeassistant.components.stream.worker.SegmentBuffer.discontinuity",
|
||||
"homeassistant.components.stream.worker.StreamState.discontinuity",
|
||||
side_effect=sync.blocking_discontinuity,
|
||||
autospec=True,
|
||||
):
|
||||
|
||||
@@ -38,8 +38,8 @@ from homeassistant.components.stream.const import (
|
||||
)
|
||||
from homeassistant.components.stream.core import StreamSettings
|
||||
from homeassistant.components.stream.worker import (
|
||||
SegmentBuffer,
|
||||
StreamEndedError,
|
||||
StreamState,
|
||||
StreamWorkerError,
|
||||
stream_worker,
|
||||
)
|
||||
@@ -255,6 +255,12 @@ class MockPyAv:
|
||||
return self.container
|
||||
|
||||
|
||||
def run_worker(hass, stream, stream_source):
|
||||
"""Run the stream worker under test."""
|
||||
stream_state = StreamState(hass, stream.outputs)
|
||||
stream_worker(stream_source, {}, stream_state, threading.Event())
|
||||
|
||||
|
||||
async def async_decode_stream(hass, packets, py_av=None):
|
||||
"""Start a stream worker that decodes incoming stream packets into output segments."""
|
||||
stream = Stream(hass, STREAM_SOURCE, {})
|
||||
@@ -268,9 +274,8 @@ async def async_decode_stream(hass, packets, py_av=None):
|
||||
"homeassistant.components.stream.core.StreamOutput.put",
|
||||
side_effect=py_av.capture_buffer.capture_output_segment,
|
||||
):
|
||||
segment_buffer = SegmentBuffer(hass, stream.outputs)
|
||||
try:
|
||||
stream_worker(STREAM_SOURCE, {}, segment_buffer, threading.Event())
|
||||
run_worker(hass, stream, STREAM_SOURCE)
|
||||
except StreamEndedError:
|
||||
# Tests only use a limited number of packets, then the worker exits as expected. In
|
||||
# production, stream ending would be unexpected.
|
||||
@@ -288,8 +293,7 @@ async def test_stream_open_fails(hass):
|
||||
stream.add_provider(HLS_PROVIDER)
|
||||
with patch("av.open") as av_open, pytest.raises(StreamWorkerError):
|
||||
av_open.side_effect = av.error.InvalidDataError(-2, "error")
|
||||
segment_buffer = SegmentBuffer(hass, stream.outputs)
|
||||
stream_worker(STREAM_SOURCE, {}, segment_buffer, threading.Event())
|
||||
run_worker(hass, stream, STREAM_SOURCE)
|
||||
await hass.async_block_till_done()
|
||||
av_open.assert_called_once()
|
||||
|
||||
@@ -695,10 +699,7 @@ async def test_worker_log(hass, caplog):
|
||||
|
||||
with patch("av.open") as av_open, pytest.raises(StreamWorkerError) as err:
|
||||
av_open.side_effect = av.error.InvalidDataError(-2, "error")
|
||||
segment_buffer = SegmentBuffer(hass, stream.outputs)
|
||||
stream_worker(
|
||||
"https://abcd:efgh@foo.bar", {}, segment_buffer, threading.Event()
|
||||
)
|
||||
run_worker(hass, stream, "https://abcd:efgh@foo.bar")
|
||||
await hass.async_block_till_done()
|
||||
assert str(err.value) == "Error opening stream https://****:****@foo.bar"
|
||||
assert "https://abcd:efgh@foo.bar" not in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user