mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-02 20:22:15 +02:00
Two bugs surfaced while investigating camera reconnect behaviour in #925. The camera page briefly displayed "Reconnecting attempt 6 of 5" before giving up, because the attempt counter could be incremented to the maximum while the reconnect banner was still rendering. The displayed value is now clamped to the configured maximum. Every failed ffmpeg spawn logged the full ~20-line ffmpeg version, configuration, and lib* banner, producing hundreds of lines of noise per failed camera click (one reported click produced 555 log lines across 30 retries). A new _summarize_ffmpeg_stderr helper strips the banner and caps output at the last 10 meaningful lines, applied at all three stderr log sites (immediate-failure, stream-ended, read-timeout). Covered by unit tests for empty input, banner stripping, line cap, blank-line filtering, and banner-only input. The underlying "camera service stops accepting connections after prolonged uptime" behaviour in the X1C firmware is still under investigation — these two fixes are independent of that root cause.
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
"""Tests for _summarize_ffmpeg_stderr (#925).
|
|
|
|
The ffmpeg banner (version / build / configuration / lib*) dumps ~20 lines
|
|
before any actual error. Before this fix, every failed camera retry logged
|
|
the full banner, producing hundreds of lines per failure — see #925 where a
|
|
single click produced 555 lines across 30 retries. The helper strips the
|
|
banner so logs stay focused on the real error.
|
|
"""
|
|
|
|
from backend.app.api.routes.camera import _summarize_ffmpeg_stderr
|
|
|
|
_FAKE_BANNER = """ffmpeg version 7.1.3-0+deb13u1 Copyright (c) 2000-2025 the FFmpeg developers
|
|
built with gcc 14 (Debian 14.2.0-19)
|
|
configuration: --prefix=/usr --extra-version=0+deb13u1 --toolchain=hardened --enable-gpl --enable-gnutls
|
|
libavutil 59. 39.100 / 59. 39.100
|
|
libavcodec 61. 19.101 / 61. 19.101
|
|
libavformat 61. 7.100 / 61. 7.100
|
|
libavdevice 61. 3.100 / 61. 3.100
|
|
libavfilter 10. 4.100 / 10. 4.100
|
|
libswscale 8. 3.100 / 8. 3.100
|
|
libswresample 5. 3.100 / 5. 3.100
|
|
libpostproc 58. 3.100 / 58. 3.100
|
|
"""
|
|
|
|
|
|
def test_empty_input():
|
|
assert _summarize_ffmpeg_stderr("") == ""
|
|
assert _summarize_ffmpeg_stderr(None) == ""
|
|
|
|
|
|
def test_keeps_error_lines_drops_banner():
|
|
stderr = _FAKE_BANNER + (
|
|
"[in#0 @ 0x64a7cd6350c0] Error opening input: Invalid data found when processing input\n"
|
|
"Error opening input file rtsp://[CREDENTIALS]@192.0.2.1:322/streaming/live/1.\n"
|
|
"Error opening input files: Invalid data found when processing input\n"
|
|
)
|
|
result = _summarize_ffmpeg_stderr(stderr)
|
|
|
|
# Banner gone
|
|
assert "ffmpeg version" not in result
|
|
assert "configuration:" not in result
|
|
assert "libavcodec" not in result
|
|
|
|
# Real errors preserved
|
|
assert "Error opening input: Invalid data found when processing input" in result
|
|
assert "Error opening input file rtsp" in result
|
|
|
|
|
|
def test_caps_at_10_lines():
|
|
stderr = _FAKE_BANNER + "\n".join(f"error line {i}" for i in range(25))
|
|
result = _summarize_ffmpeg_stderr(stderr)
|
|
|
|
lines = result.splitlines()
|
|
assert len(lines) == 10
|
|
# Keeps the *last* 10 lines (most recent errors closest to failure)
|
|
assert lines[-1] == "error line 24"
|
|
assert lines[0] == "error line 15"
|
|
|
|
|
|
def test_drops_blank_lines():
|
|
stderr = "real error\n\n\n \nsecond error\n"
|
|
result = _summarize_ffmpeg_stderr(stderr)
|
|
assert result == "real error\nsecond error"
|
|
|
|
|
|
def test_banner_only_returns_empty():
|
|
"""If ffmpeg prints only the banner (no errors), the summary should be empty."""
|
|
assert _summarize_ffmpeg_stderr(_FAKE_BANNER) == ""
|