test_video_fetch.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. """V3-M2A: video_fetch download + compress + data URL (all mocked)."""
  2. from __future__ import annotations
  3. import base64
  4. import httpx
  5. import pytest
  6. from content_agent.integrations import video_fetch
  7. from content_agent.integrations.video_fetch import VideoFetchError, fetch_and_compress
  8. class FakeHttpClient:
  9. def __init__(self, *, content=b"rawvideo", status=200, error=None):
  10. self.content = content
  11. self.status = status
  12. self.error = error
  13. self.calls = []
  14. def get(self, url, *, headers, follow_redirects, timeout):
  15. self.calls.append({"url": url, "headers": headers})
  16. if self.error:
  17. raise self.error
  18. return httpx.Response(
  19. self.status, content=self.content, request=httpx.Request("GET", url)
  20. )
  21. def _patch_compress(monkeypatch, out=b"\x00\x00\x00\x18ftypmp42compressed"):
  22. monkeypatch.setattr(video_fetch, "_compress", lambda raw, exe, **kwargs: out)
  23. def test_fetch_builds_data_url(monkeypatch):
  24. _patch_compress(monkeypatch)
  25. out = fetch_and_compress("http://v/x", "douyin", http_client=FakeHttpClient(), ffmpeg_exe="ffmpeg")
  26. assert out.startswith("data:video/mp4;base64,")
  27. decoded = base64.b64decode(out.split(",", 1)[1])
  28. assert decoded.startswith(b"\x00\x00\x00\x18ftyp")
  29. def test_fetch_uses_platform_headers(monkeypatch):
  30. _patch_compress(monkeypatch)
  31. for platform, ua_token, referer in [
  32. ("douyin", "iPhone", "https://www.douyin.com/"),
  33. ("shipinhao", "Windows", "https://channels.weixin.qq.com/"),
  34. ]:
  35. client = FakeHttpClient()
  36. fetch_and_compress("http://v/x", platform, http_client=client, ffmpeg_exe="ffmpeg")
  37. headers = client.calls[0]["headers"]
  38. assert ua_token in headers["User-Agent"]
  39. assert headers["Referer"] == referer
  40. def test_fetch_missing_play_url_raises():
  41. with pytest.raises(VideoFetchError, match="missing play_url"):
  42. fetch_and_compress("", "douyin", http_client=FakeHttpClient())
  43. def test_fetch_download_failure_raises():
  44. client = FakeHttpClient(error=httpx.ConnectError("boom"))
  45. with pytest.raises(VideoFetchError, match="download failed"):
  46. fetch_and_compress("http://v/x", "douyin", http_client=client, ffmpeg_exe="ffmpeg")
  47. def test_fetch_enforces_total_download_timeout(monkeypatch):
  48. _patch_compress(monkeypatch)
  49. ticks = iter([0.0, 0.0, 31.0, 31.0])
  50. with pytest.raises(VideoFetchError, match="download timeout") as exc_info:
  51. fetch_and_compress(
  52. "http://v/x",
  53. "douyin",
  54. http_client=FakeHttpClient(),
  55. ffmpeg_exe="ffmpeg",
  56. timeout_seconds=30.0,
  57. clock=lambda: next(ticks),
  58. )
  59. assert exc_info.value.metrics["total_duration_ms"] == 31000
  60. def test_fetch_oversize_raises(monkeypatch):
  61. _patch_compress(monkeypatch, out=b"x" * (video_fetch.MAX_INLINE_BYTES + 1))
  62. with pytest.raises(VideoFetchError, match="oversize"):
  63. fetch_and_compress("http://v/x", "douyin", http_client=FakeHttpClient(), ffmpeg_exe="ffmpeg")