diff options
Diffstat (limited to 'packages/meshbay-node/tests/test_stream_subtitle_tracks.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_stream_subtitle_tracks.py | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/packages/meshbay-node/tests/test_stream_subtitle_tracks.py b/packages/meshbay-node/tests/test_stream_subtitle_tracks.py index 9a09edb..d3bcc8b 100644 --- a/packages/meshbay-node/tests/test_stream_subtitle_tracks.py +++ b/packages/meshbay-node/tests/test_stream_subtitle_tracks.py @@ -38,7 +38,11 @@ from meshbay_common.crypto import generate_gek from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes from meshbay_node.indexer.group_index import GroupIndex from meshbay_node.media_probe import TEXT_SUBTITLE_CODECS -from meshbay_node.transport.webrtc_server import WebRTCPeerSession, _probe_video +from meshbay_node.transport.webrtc_server import ( + WebRTCPeerSession, + _probe_video, + _subtitle_timeout_for, +) from conftest import needs_subprocess, one_root @@ -356,3 +360,52 @@ async def test_the_result_is_fetched_through_the_ordinary_chunk_path(tmp_path): plain = decrypt_chunk_aes(key, chunk["nonce"], chunk["ct"]) assert plain.decode("utf-8").startswith("WEBVTT") assert _CUE_WORD[2] in plain.decode("utf-8") + + +def test_the_budget_grows_with_the_file_not_with_the_subtitle(): + """Extraction demuxes the whole container, so the file sets the cost. + + Measured on a library held on an external disk: 9.8 s per GB — 36 s for a + 3.9 GB title and 71 s for a 7.3 GB one. A flat 60 s therefore worked on + most of a library and failed on the big films, which is indistinguishable + from a broken feature to whoever is watching one. The allowance is three + times the measured rate, so a slower disk still finishes. + """ + assert _subtitle_timeout_for(500_000_000) == 60 # small file, the floor + assert _subtitle_timeout_for(7_310_000_000) > 71 * 2 # the film that timed out + assert _subtitle_timeout_for(3_900_000_000) > 36 * 2 + # Bounded: a pathological container must not pin a transcode slot for ever. + assert _subtitle_timeout_for(500_000_000_000) == 900 + # Monotonic, or a bigger file could be given less time than a smaller one. + budgets = [_subtitle_timeout_for(int(gb * 1e9)) for gb in (1, 4, 8, 20, 100)] + assert budgets == sorted(budgets) + + +@pytest.mark.asyncio +async def test_two_requests_for_one_track_extract_once(tmp_path): + """Two clicks seconds apart used to run two whole extractions. + + The cache is consulted on the way in, so the second request missed it + while the first was still running: seen in the log as two identical + extractions of one 4.3 GB file overlapping, each holding a transcode slot + and reading the file end to end. The latecomer waits for the answer the + first is already producing, and both are answered. + """ + clip = tmp_path / "clip.mp4" + _make_subtitled_clip(clip) + gek = generate_gek() + session, file_id = _session(clip, gek) + + import asyncio + await asyncio.gather( + session._do_subtitle_request({"file_id": file_id, "track": 1}), + session._do_subtitle_request({"file_id": file_id, "track": 1}), + ) + + replies = [m for m in session.sent if m.get("type") == "subtitle_resp"] + assert len(replies) == 2, f"both callers must be answered: {session.sent}" + assert replies[0]["hash"] == replies[1]["hash"] + assert session._ctx["media_cache"].puts == 1, ( + "the second request ran its own extraction instead of joining the first") + assert not session._ctx["_subtitle_inflight"], ( + "the in-flight entry outlived the extraction and would block the next one") |