"""EngineOwner 단위 테스트 — OOM 강등 체인, attempted_profiles 영속화, 우선순위.""" from __future__ import annotations import pytest from luke_scribe.engine.base import TranscriptionOptions from luke_scribe.engine.owner import MAX_DOWNGRADES, EngineOwner, InferenceRequest from luke_scribe.errors import OutOfMemory class OOMFakeEngine: """첫 N번 호출에서 OOM, 이후 성공하는 mock.""" def __init__(self, oom_calls: int = 0) -> None: self.oom_calls = oom_calls self.calls: list[dict] = [] self.closed = False def transcribe(self, audio_path, options, should_cancel=None, download_progress=None): self.calls.append({"device": options.device, "compute_type": options.compute_type}) if len(self.calls) <= self.oom_calls: raise OutOfMemory("CUDA OOM (mock)") return type("O", (), {"segments": iter([]), "info": {}})() def unload_all(self): self.closed = True def _opts(**kw) -> TranscriptionOptions: kw.setdefault("model", "large-v3-turbo") kw.setdefault("device", "cuda:0") kw.setdefault("compute_type", "float16") return TranscriptionOptions(**kw) class _SegFakeEngine: """emit_hypothesis 테스트용 — WAV 경로 기록 + 세그먼트 반환.""" def __init__(self) -> None: self.path = None def transcribe(self, audio_path, options, should_cancel=None, download_progress=None): self.path = audio_path segs = [ { "start": 0.0, "end": 1.2, "text": "안녕하세요", "avg_logprob": -0.2, "no_speech_prob": 0.01, } ] return type("O", (), {"segments": iter(segs), "info": {"language": "ko"}})() def unload_all(self): pass def _bare_owner(engine) -> EngineOwner: import threading from luke_scribe.config import Settings owner = EngineOwner.__new__(EngineOwner) owner.settings = Settings(_env_file=None) owner._engine = engine owner._lock = threading.Lock() owner._realtime_priority = threading.Lock() owner._stats = {"jobs": 0, "downgrades": 0, "oom": 0} return owner def test_pcm16_to_wav_header(): import struct from luke_scribe.engine.owner import _pcm16_to_wav wav = _pcm16_to_wav(b"\x00\x00" * 8000) # 1초 (16kHz mono) assert wav[:4] == b"RIFF" assert wav[8:12] == b"WAVE" assert wav[12:16] == b"fmt " sr = struct.unpack("