external_camera.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536
  1. """Stand-ins for the ffmpeg subprocess the external-camera paths spawn.
  2. Both RTSP paths in ``backend.app.services.external_camera`` build an argv and
  3. hand it to ``asyncio.create_subprocess_exec``. Tests that care about *what we
  4. asked ffmpeg to do* — the SSRF guards, the probe settings — need to see that
  5. argv without an ffmpeg binary being involved, so these patch the lookup and the
  6. spawn and record the call.
  7. """
  8. from unittest.mock import AsyncMock, MagicMock, patch
  9. def fake_ffmpeg():
  10. """Pretend ffmpeg is installed, so the paths get as far as building argv."""
  11. return patch("backend.app.services.external_camera.get_ffmpeg_path", return_value="/usr/bin/ffmpeg")
  12. def spawn_spy(returncode: int | None = 0, stdout: bytes = b"\xff\xd8" + b"\x00" * 200):
  13. """Stand in for the ffmpeg subprocess, recording the argv it was handed.
  14. The streaming path reads until EOF, so stdout.read returns b"" and the
  15. generator finishes immediately — these tests are about whether ffmpeg was
  16. launched and with what, not about frame extraction.
  17. """
  18. process = MagicMock()
  19. process.returncode = returncode
  20. process.communicate = AsyncMock(return_value=(stdout, b""))
  21. process.stdout.read = AsyncMock(return_value=b"")
  22. process.stderr.read = AsyncMock(return_value=b"")
  23. process.wait = AsyncMock(return_value=returncode)
  24. process.kill = MagicMock()
  25. process.terminate = MagicMock()
  26. return patch(
  27. "backend.app.services.external_camera.asyncio.create_subprocess_exec",
  28. new=AsyncMock(return_value=process),
  29. )