fix: make container media diagnostics reliable

This commit is contained in:
drockhollaback
2026-08-27 21:27:41 -04:00
parent c9f2991055
commit 46e92149d9
5 changed files with 113 additions and 4 deletions
+4 -1
View File
@@ -1,7 +1,10 @@
ARG M4B_TOOL_IMAGE=sandreas/m4b-tool:0.5.2
FROM ${M4B_TOOL_IMAGE}
RUN apk add --no-cache python3 py3-pip
# Alpine's ffmpeg package supplies ffprobe. /usr/local/bin/ffmpeg from the
# upstream image remains first on PATH for its specialized codec build.
RUN apk add --no-cache ffmpeg python3 py3-pip \
&& ffprobe -version
WORKDIR /app
COPY pyproject.toml /app/
+10 -1
View File
@@ -18,6 +18,11 @@ from .tui import AudiobookApp, TerminalUI
_DEFAULT_CONFIG = Path("config.toml")
_EXECUTABLES = ("m4b-tool", "ffmpeg", "ffprobe")
_VERSION_ARGUMENTS = {
"m4b-tool": ("--version",),
"ffmpeg": ("-version",),
"ffprobe": ("-version",),
}
def _parser() -> argparse.ArgumentParser:
@@ -43,7 +48,11 @@ def _version(executable: str) -> str | None:
return None
try:
result = subprocess.run(
(executable, "--version"), text=True, capture_output=True, check=False, timeout=5
(executable, *_VERSION_ARGUMENTS[executable]),
text=True,
capture_output=True,
check=False,
timeout=5,
)
except (OSError, subprocess.TimeoutExpired):
return None
+3 -2
View File
@@ -2,6 +2,9 @@
set -eu
m4b-tool --version
ffmpeg -version
ffprobe -version
merge_help=$(m4b-tool merge --help 2>&1)
for required_option in \
--jobs \
@@ -26,8 +29,6 @@ done
if [ "${AUDIOBOOK_SMOKE_OPTION_GUARD_ONLY:-0}" = 1 ]; then
exit 0
fi
ffmpeg -version
ffprobe -version
smoke_root=$(mktemp -d "${TMPDIR:-/tmp}/audiobook-tui-smoke.XXXXXX")
trap 'rm -rf "$smoke_root"' EXIT HUP INT TERM
+29
View File
@@ -1,6 +1,8 @@
from io import StringIO
from pathlib import Path
import pytest
import app.main as main_module
from app.models import Roots, Settings
@@ -20,6 +22,33 @@ def test_doctor_is_read_only_and_reports_missing_config(tmp_path: Path, capsys)
assert "configuration" in capsys.readouterr().out.lower()
@pytest.mark.parametrize(
("executable", "expected_argument"),
(("m4b-tool", "--version"), ("ffmpeg", "-version"), ("ffprobe", "-version")),
)
def test_version_uses_each_executables_supported_version_argument(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
executable: str,
expected_argument: str,
) -> None:
binary_directory = tmp_path / "bin"
binary_directory.mkdir()
fake = binary_directory / executable
fake.write_text(
"#!/bin/sh\n"
f'if [ "$#" -ne 1 ] || [ "$1" != "{expected_argument}" ]; then\n'
" exit 64\n"
"fi\n"
f"printf '%s\\n' '{executable} expected version'\n",
encoding="utf-8",
)
fake.chmod(0o755)
monkeypatch.setenv("PATH", str(binary_directory))
assert main_module._version(executable) == f"{executable} expected version"
def test_doctor_checks_an_existing_destination_root_not_just_its_parent(tmp_path: Path) -> None:
pending = tmp_path / "pending"
pending.mkdir()
+67
View File
@@ -27,6 +27,27 @@ def _service() -> dict[str, object]:
return compose["services"]["audiobook-tui"]
def _write_fake_media_versions(
binary_directory: Path, *, ffprobe_available: bool = True
) -> None:
for executable in ("ffmpeg", "ffprobe"):
fake = binary_directory / executable
if executable == "ffprobe" and not ffprobe_available:
body = (
"#!/bin/sh\n"
"printf '%s\\n' 'ffprobe unavailable' >&2\n"
"exit 127\n"
)
else:
body = (
"#!/bin/sh\n"
"[ \"${1:-}\" = -version ] || exit 64\n"
f"printf '%s\\n' '{executable} fake'\n"
)
fake.write_text(body, encoding="utf-8")
fake.chmod(0o755)
def test_compose_has_tty_stdin_and_four_mounts() -> None:
service = _service()
@@ -130,6 +151,17 @@ def test_image_pin_and_application_entrypoint_are_explicit() -> None:
assert 'ENTRYPOINT ["/usr/local/bin/audiobook-entrypoint"]' in dockerfile
def test_image_installs_ffprobe_and_smoke_checks_its_supported_version_flag() -> None:
dockerfile = Path("Dockerfile").read_text(encoding="utf-8").replace("\\\n", " ")
smoke = Path("scripts/container-smoke.sh").read_text(encoding="utf-8")
runtime_install = next(
line for line in dockerfile.splitlines() if line.startswith("RUN apk add ")
)
assert "ffmpeg" in runtime_install.split()
assert "ffprobe -version" in smoke
def test_container_smoke_script_is_copied_to_its_documented_path() -> None:
dockerfile = Path("Dockerfile").read_text(encoding="utf-8")
smoke = Path("scripts/container-smoke.sh").read_text(encoding="utf-8")
@@ -162,6 +194,7 @@ def test_container_smoke_upgrade_guard_rejects_each_missing_planner_option(
encoding="utf-8",
)
fake_m4b.chmod(0o755)
_write_fake_media_versions(binary_directory)
help_text = " ".join(option for option in PLANNER_OPTIONS if option != missing)
result = subprocess.run(
@@ -197,6 +230,7 @@ def test_container_smoke_upgrade_guard_accepts_complete_planner_interface(
encoding="utf-8",
)
fake_m4b.chmod(0o755)
_write_fake_media_versions(binary_directory)
result = subprocess.run(
("sh", "scripts/container-smoke.sh"),
@@ -212,3 +246,36 @@ def test_container_smoke_upgrade_guard_accepts_complete_planner_interface(
)
assert result.returncode == 0, result.stderr
def test_container_smoke_preflight_rejects_unavailable_ffprobe(tmp_path: Path) -> None:
binary_directory = tmp_path / "bin"
binary_directory.mkdir()
fake_m4b = binary_directory / "m4b-tool"
fake_m4b.write_text(
"#!/bin/sh\n"
"if [ \"${1:-}\" = merge ] && [ \"${2:-}\" = --help ]; then\n"
" printf '%s\\n' \"$FAKE_M4B_HELP\"\n"
"else\n"
" printf '%s\\n' 'm4b-tool fake'\n"
"fi\n",
encoding="utf-8",
)
fake_m4b.chmod(0o755)
_write_fake_media_versions(binary_directory, ffprobe_available=False)
result = subprocess.run(
("sh", "scripts/container-smoke.sh"),
env={
**os.environ,
"PATH": f"{binary_directory}:{os.environ['PATH']}",
"FAKE_M4B_HELP": " ".join(PLANNER_OPTIONS),
"AUDIOBOOK_SMOKE_OPTION_GUARD_ONLY": "1",
},
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 127
assert "ffprobe unavailable" in result.stderr