Files
2026-10-07 04:46:26 -07:00

122 lines
3.9 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""Unit coverage for :mod:`fastvideo.entrypoints.streaming.worker`.
The full ``worker_main`` loop runs in a subprocess and is exercised via
``test_gpu_pool.py``'s subprocess integration tests. This file covers
the in-process pieces:
* the two-segment warmup feeds segment 1's continuation state into
segment 2 so both compile branches are primed before the worker
reports ready
* result-shape extractors handle both attribute-style and dict-style
generator returns
"""
from __future__ import annotations
import os
import queue
import threading
from dataclasses import dataclass, field
from typing import Any
import fastvideo.envs as envs
from fastvideo.api.schema import (
ContinuationState,
GeneratorConfig,
GenerationRequest,
WarmupConfig,
)
from fastvideo.entrypoints.streaming.worker import (
_extract_continuation_state,
_warmup_worker,
worker_main,
)
@dataclass
class _RecordingGenerator:
"""Captures the requests passed to ``generate`` and returns a
canned :class:`ContinuationState` on the first call so the warmup
can feed it into the second call.
"""
state_to_return: ContinuationState | None = field(default_factory=lambda: ContinuationState(
kind="ltx2.v1",
payload={
"schema_version": 1,
"segment_index": 1
},
))
requests: list[GenerationRequest] = field(default_factory=list)
def generate(self, request: GenerationRequest) -> dict[str, Any]:
self.requests.append(request)
return {"frames": [], "state": self.state_to_return}
class TestWarmupTwoSegment:
def test_warmup_runs_segment_one_then_segment_two_with_returned_state(self) -> None:
gen = _RecordingGenerator()
_warmup_worker(gen, WarmupConfig(enabled=True, prompt="warm"))
assert len(gen.requests) == 2
seg1 = gen.requests[0]
assert seg1.state is None
assert seg1.output.return_state is True
seg2 = gen.requests[1]
assert seg2.state is gen.state_to_return
def test_warmup_passes_through_when_no_state_returned(self) -> None:
gen = _RecordingGenerator(state_to_return=None)
_warmup_worker(gen, WarmupConfig(enabled=True, prompt="warm"))
assert len(gen.requests) == 2
assert gen.requests[1].state is None
class TestExtractContinuationState:
def test_extracts_from_attribute(self) -> None:
class _R:
state = ContinuationState(kind="k", payload={})
assert _extract_continuation_state(_R()).kind == "k"
def test_extracts_from_dict(self) -> None:
state = ContinuationState(kind="k", payload={})
assert _extract_continuation_state({"state": state}) is state
def test_returns_none_for_missing(self) -> None:
assert _extract_continuation_state({}) is None
assert _extract_continuation_state(object()) is None
def test_worker_rejects_external_launcher_before_generator_construction(env_overrides) -> None:
# worker_main() pins CUDA_VISIBLE_DEVICES for the worker process it normally
# runs in. Here it runs in the pytest process, so restore the test
# process's value afterwards.
env_overrides.enter_context(envs.override_external("CUDA_VISIBLE_DEVICES",
os.environ.get("CUDA_VISIBLE_DEVICES")))
result_queue: queue.Queue = queue.Queue()
config = GeneratorConfig(model_path="/models/fake")
config.engine.execution_backend = "external_launcher"
worker_main(
gpu_id=0,
worker_id="worker-0",
generator_config=config,
warmup_config=WarmupConfig(enabled=False),
job_queue=queue.Queue(),
result_queue=result_queue,
shutdown_event=threading.Event(),
)
result = result_queue.get_nowait()
assert result["kind"] == "error"
assert "external_launcher is supported only" in result["error"]
assert "streaming worker" in result["error"]