fix(gpu-encoder): fix unit tests for split relay URLs
- Update tests to use _relay_put_url/_relay_internal_url instead of removed _relay_url - Fix _fake_response to support chunked read(size) used by _download_to_file - Fix regex match for error message (rc=1 not ffmpeg_rc=1) - Add tests for internal/external URL separation and fallback behavior
This commit is contained in:
committed by
saas-backend
parent
30f16c4771
commit
66dc73c8d3
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
@@ -34,6 +33,7 @@ def client():
|
||||
return GpuEncoderClient(
|
||||
endpoint="http://gpu.example.com:8900",
|
||||
relay_base_url="http://api.example.com",
|
||||
relay_internal_base_url="http://api-internal:8000",
|
||||
sync_timeout=60,
|
||||
health_timeout=2,
|
||||
relay_secret="test-secret",
|
||||
@@ -41,15 +41,20 @@ def client():
|
||||
|
||||
|
||||
def _fake_response(status: int = 200, body: dict | bytes | None = None, headers=None):
|
||||
"""Fake HTTPResponse that supports chunked read(size) used by _download_to_file."""
|
||||
if isinstance(body, dict):
|
||||
data = json.dumps(body).encode("utf-8")
|
||||
elif body is None:
|
||||
data = b""
|
||||
else:
|
||||
data = body
|
||||
|
||||
# Use a real BytesIO so read(size) works for chunked downloads
|
||||
bio = BytesIO(data)
|
||||
|
||||
resp = mock.MagicMock(spec=HTTPResponse)
|
||||
resp.status = status
|
||||
resp.read.return_value = data
|
||||
resp.read.side_effect = lambda n=-1: bio.read(n)
|
||||
resp.__enter__ = mock.MagicMock(return_value=resp)
|
||||
resp.__exit__ = mock.MagicMock(return_value=False)
|
||||
return resp
|
||||
@@ -111,36 +116,65 @@ class TestPostSync:
|
||||
)
|
||||
assert res["status"] == "completed"
|
||||
assert res["ffmpeg_rc"] == 0
|
||||
# verify request sent to sync endpoint
|
||||
req = m.call_args[0][0]
|
||||
assert req.full_url == "http://gpu.example.com:8900/api/render/sync"
|
||||
|
||||
def test_ffmpeg_failure_raises(self, client):
|
||||
body = {"status": "failed", "ffmpeg_rc": 1, "message": "Invalid data found"}
|
||||
with mock.patch("urllib.request.urlopen", return_value=_fake_response(body=body)):
|
||||
with pytest.raises(GpuEncodeError, match="ffmpeg_rc=1"):
|
||||
with pytest.raises(GpuEncodeError, match="rc=1"):
|
||||
client._post_sync(
|
||||
{"inputs": {}, "ffmpeg_args": [], "output_url": "", "timeout": 10}, mezzanine_path=Path("/tmp/x")
|
||||
{"inputs": {}, "ffmpeg_args": [], "output_url": "", "timeout": 10},
|
||||
mezzanine_path=Path("/tmp/x"),
|
||||
)
|
||||
|
||||
def test_http_4xx_raises(self, client):
|
||||
err = urllib.error.HTTPError(
|
||||
url="http://gpu/render/sync", code=422, msg="Unprocessable", hdrs={}, fp=BytesIO(b"bad request")
|
||||
url="http://gpu/render/sync",
|
||||
code=422,
|
||||
msg="Unprocessable",
|
||||
hdrs={},
|
||||
fp=BytesIO(b"bad request"),
|
||||
)
|
||||
with mock.patch("urllib.request.urlopen", side_effect=err):
|
||||
with pytest.raises(GpuEncodeError, match="HTTP 422"):
|
||||
client._post_sync(
|
||||
{"inputs": {}, "ffmpeg_args": [], "output_url": "", "timeout": 10}, mezzanine_path=Path("/tmp/x")
|
||||
{"inputs": {}, "ffmpeg_args": [], "output_url": "", "timeout": 10},
|
||||
mezzanine_path=Path("/tmp/x"),
|
||||
)
|
||||
|
||||
|
||||
class TestRelayUrl:
|
||||
def test_url_contains_token_and_key(self, client):
|
||||
url = client._relay_url("abc123", "secret!")
|
||||
def test_put_url_uses_external_base(self, client):
|
||||
url = client._relay_put_url("abc123", "secret!")
|
||||
assert "abc123" in url
|
||||
assert "token=secret%21" in url # urlencoded
|
||||
assert url.startswith("http://api.example.com/api/v1/internal/gpu-relay/")
|
||||
|
||||
def test_internal_url_uses_internal_base(self, client):
|
||||
url = client._relay_internal_url("abc123", "s")
|
||||
assert url.startswith("http://api-internal:8000/api/v1/internal/gpu-relay/abc123")
|
||||
|
||||
def test_internal_url_falls_back_to_external_when_not_set(self):
|
||||
c = GpuEncoderClient(
|
||||
endpoint="http://gpu",
|
||||
relay_base_url="http://api.example.com",
|
||||
relay_secret="s",
|
||||
)
|
||||
put = c._relay_put_url("k", "s")
|
||||
internal = c._relay_internal_url("k", "s")
|
||||
assert put.startswith("http://api.example.com/")
|
||||
# When internal not set, internal_url falls back to external base
|
||||
assert internal == put
|
||||
|
||||
def test_encode_uses_different_put_and_get_urls(self, client):
|
||||
"""encode_mezzanine_to_output should use external URL for PUT and internal for GET/DELETE."""
|
||||
put_url = client._relay_put_url("k", "test-secret")
|
||||
get_url = client._relay_internal_url("k", "test-secret")
|
||||
assert "api.example.com" in put_url
|
||||
assert "api-internal:8000" in get_url
|
||||
assert put_url != get_url
|
||||
|
||||
|
||||
class TestGetRelaySecret:
|
||||
def test_explicit_secret_used(self, client):
|
||||
@@ -175,9 +209,3 @@ class TestDownloadToFile:
|
||||
with pytest.raises(GpuEncodeError, match="empty file"):
|
||||
client._download_to_file("http://relay/k", out)
|
||||
assert not out.exists()
|
||||
|
||||
|
||||
class TestFfmpegOutputToMezzanineIntegration:
|
||||
"""_ffmpeg_output_to_mezzanine is on UnifiedRenderService; unit-tested there via mocks."""
|
||||
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user