97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
from unittest.mock import MagicMock, patch
|
|
|
|
_SAMPLE_FEED = (
|
|
b'<?xml version="1.0" encoding="UTF-8"?>'
|
|
b"<rss version=\"2.0\"><channel>"
|
|
b"<item><title>Test</title></item>"
|
|
b"</channel></rss>"
|
|
)
|
|
|
|
|
|
def _mock_upstream(content=_SAMPLE_FEED, raise_error=False):
|
|
m = MagicMock()
|
|
m.content = content
|
|
if raise_error:
|
|
m.raise_for_status.side_effect = Exception("HTTP error")
|
|
else:
|
|
m.raise_for_status = MagicMock()
|
|
return m
|
|
|
|
|
|
# ── Frontend routes ───────────────────────────────────────────────────────────
|
|
|
|
def test_index_returns_200(app_client):
|
|
resp = app_client.get("/")
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def test_reader_valid_lang_returns_200(app_client):
|
|
resp = app_client.get("/sk/")
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def test_reader_invalid_lang_redirects(app_client):
|
|
resp = app_client.get("/xx/")
|
|
assert resp.status_code == 302
|
|
assert "/sk/" in resp.headers["Location"]
|
|
|
|
|
|
# ── Media proxy ───────────────────────────────────────────────────────────────
|
|
|
|
def test_media_proxy_allowed_host(app_client):
|
|
mock_resp = MagicMock()
|
|
mock_resp.content = b"imgdata"
|
|
mock_resp.headers = {"Content-Type": "image/jpeg"}
|
|
mock_resp.raise_for_status = MagicMock()
|
|
with patch("app.requests.get", return_value=mock_resp):
|
|
resp = app_client.get("/media?url=https://cdn.telesco.pe/photo.jpg")
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def test_media_proxy_forbidden_host(app_client):
|
|
resp = app_client.get("/media?url=https://evil.com/img.jpg")
|
|
assert resp.status_code == 403
|
|
|
|
|
|
# ── Feed proxy ────────────────────────────────────────────────────────────────
|
|
|
|
def test_feed_proxy_cache_miss(app_client):
|
|
with patch("app.requests.get", return_value=_mock_upstream()), \
|
|
patch("app.translate_feed", return_value=_SAMPLE_FEED):
|
|
resp = app_client.get("/sk/telegram/channel/test")
|
|
assert resp.status_code == 200
|
|
assert resp.headers["X-Cache"] == "MISS"
|
|
|
|
|
|
def test_feed_proxy_cache_hit(app_client):
|
|
with patch("app.requests.get", return_value=_mock_upstream()) as mock_get, \
|
|
patch("app.translate_feed", return_value=_SAMPLE_FEED):
|
|
app_client.get("/sk/telegram/channel/test") # populate cache
|
|
mock_get.reset_mock()
|
|
resp = app_client.get("/sk/telegram/channel/test")
|
|
assert resp.status_code == 200
|
|
assert resp.headers["X-Cache"] == "HIT"
|
|
mock_get.assert_not_called()
|
|
|
|
|
|
def test_feed_proxy_304_on_matching_etag(app_client):
|
|
with patch("app.requests.get", return_value=_mock_upstream()), \
|
|
patch("app.translate_feed", return_value=_SAMPLE_FEED):
|
|
first = app_client.get("/sk/telegram/channel/test")
|
|
etag = first.headers["ETag"]
|
|
second = app_client.get(
|
|
"/sk/telegram/channel/test",
|
|
headers={"If-None-Match": etag},
|
|
)
|
|
assert second.status_code == 304
|
|
|
|
|
|
def test_feed_proxy_unknown_lang_returns_400(app_client):
|
|
resp = app_client.get("/xx/telegram/channel/test")
|
|
assert resp.status_code == 400
|
|
|
|
|
|
def test_feed_proxy_upstream_error_returns_502(app_client):
|
|
with patch("app.requests.get", side_effect=Exception("timeout")):
|
|
resp = app_client.get("/sk/telegram/channel/test")
|
|
assert resp.status_code == 502
|