diff --git a/backend/services/ffmpeg_utils.py b/backend/services/ffmpeg_utils.py index f42f7a8d..cf3f30b7 100644 --- a/backend/services/ffmpeg_utils.py +++ b/backend/services/ffmpeg_utils.py @@ -174,12 +174,12 @@ def _binary_runs(path: str) -> bool: if cached is not None: return cached try: - subprocess.run( + result = subprocess.run( [path, "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10, check=False, ) - ok = True + ok = result.returncode == 0 except (OSError, subprocess.TimeoutExpired, subprocess.SubprocessError) as e: logger.warning( "Rejecting non-runnable ffmpeg/ffprobe candidate %s: %s", diff --git a/tests/backend/services/test_ffmpeg_utils.py b/tests/backend/services/test_ffmpeg_utils.py index 56a627f1..6c06dcad 100644 --- a/tests/backend/services/test_ffmpeg_utils.py +++ b/tests/backend/services/test_ffmpeg_utils.py @@ -188,3 +188,23 @@ def test_windows_tool_candidates_derive_from_environment(monkeypatch): assert any(p.startswith("E:\\Program Files") for p in got) # env-derived Program Files assert "C:\\ffmpeg\\bin\\ffprobe.exe" in got # conventional fallbacks kept assert "D:\\ffmpeg\\bin\\ffprobe.exe" in got + + +def test_binary_probe_rejects_nonzero_exit(monkeypatch): + import sys + from services import ffmpeg_utils + monkeypatch.setattr(ffmpeg_utils, "_BINARY_OK", {}) + # Python is portable and executable, but rejects FFmpeg's -version flag. + assert not ffmpeg_utils._binary_runs(sys.executable) + + +def test_sibling_probe_rejects_nonzero_exit(monkeypatch, tmp_path): + import subprocess + from services import ffmpeg_utils + ffprobe = tmp_path / "ffprobe" + ffprobe.touch() + monkeypatch.setattr(ffmpeg_utils, "_BINARY_OK", {}) + monkeypatch.setattr(ffmpeg_utils, "resolve_ffprobe", lambda: None) + monkeypatch.setattr(ffmpeg_utils, "find_ffmpeg", lambda: str(tmp_path / "ffmpeg")) + monkeypatch.setattr(ffmpeg_utils.subprocess, "run", lambda *a, **kw: subprocess.CompletedProcess(a, 1)) + assert ffmpeg_utils.find_ffprobe() is None