Repair flaky and broken stream tests in test_hls.py, and turn back on (#45025)

* Unmark tests as flaky (though still flaky)

This put tests into the broken state where they are flaky and do not yet pass

* Fix bug in test_hls_stream with incorrect path

* Enable and de-flake HLS stream tests

Background: Tests encode a fake video them start a stream to be decoded. Test
assert on the decoded segments, however there is a race with the stream worker
which can finish decoding first, and end the stream which ereases all buffers.

Breadown of fixes:
- Fix the race conditions by adding synchronization points right before the
  stream is finalized.
- Refactor StreamOutput.put so that a patch() can block the worker
  thread.  Previously, the put call would happen in the event loop which was
  not safe to block. This is a bit of a hack, but it is the simplist possible
  code change to add this synchronization and arguably provides slightly better
  separation of responsibilities from the worker anyway.
- Fix bugs in the tests that make them not pass, likely due to changes
  introduced while the tests were disabled
- Fix case where the HLS stream view recv() call returns None, indicating
  the worker finished while the request was waiting.

The tests were previously failing anywhere from 2-5% of the time on a lightly
loaded machine doing 1k iterations.  Now, have 0% flake rate.  Tested with:
$ py.test --count=1000 tests/components/strema/test_hls.py
This commit is contained in:
Allen Porter 2021-01-11 05:34:45 -08:00 committed by GitHub
parent ed4e8cdbc5
commit 65e3661f88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 14 deletions

View file

@ -117,9 +117,13 @@ class StreamOutput:
self._cursor = segment.sequence
return segment
@callback
def put(self, segment: Segment) -> None:
"""Store output."""
self._stream.hass.loop.call_soon_threadsafe(self._async_put, segment)
@callback
def _async_put(self, segment: Segment) -> None:
"""Store output from event loop."""
# Start idle timeout when we start receiving data
if self._unsub is None:
self._unsub = async_call_later(