Files
MeshChatX/tests/backend/test_media_http_api.py

284 lines
9.3 KiB
Python

# SPDX-License-Identifier: 0BSD
"""HTTP integration tests for sticker, sticker-pack, and GIF APIs (aiohttp TestClient)."""
from __future__ import annotations
import base64
import pytest
from aiohttp import web
from aiohttp.test_utils import TestClient, TestServer
from tests.backend.media_test_assets import GZIP_TGS_512, TINY_GIF, TINY_PNG
pytestmark = pytest.mark.usefixtures("require_loopback_tcp")
def _build_aio_app(app):
routes = web.RouteTableDef()
auth_mw, mime_mw, sec_mw = app._define_routes(routes)
aio_app = web.Application(middlewares=[auth_mw, mime_mw, sec_mw])
aio_app.add_routes(routes)
return aio_app
@pytest.fixture
def web_media_app(mock_app):
mock_app.current_context.running = True
mock_app.config.auth_enabled.set(False)
return mock_app
@pytest.mark.asyncio
async def test_stickers_list_empty(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.get("/api/v1/stickers")
assert r.status == 200
body = await r.json()
assert body == {"stickers": []}
@pytest.mark.asyncio
async def test_stickers_create_get_image_export_import_roundtrip(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(TINY_PNG).decode("ascii")
async with TestClient(TestServer(aio_app)) as client:
c = await client.post(
"/api/v1/stickers",
json={
"name": " A ",
"image_type": "png",
"image_bytes": b64,
"strict": False,
},
)
assert c.status == 200
st = (await c.json())["sticker"]
sid = st["id"]
img = await client.get(f"/api/v1/stickers/{sid}/image")
assert img.status == 200
assert img.headers.get("Content-Type", "").startswith("image/png")
raw = await img.read()
assert raw == TINY_PNG
ex = await client.get("/api/v1/stickers/export")
assert ex.status == 200
doc = await ex.json()
assert doc.get("format") == "meshchatx-stickers"
assert doc.get("version") == 1
assert isinstance(doc.get("stickers"), list)
assert len(doc["stickers"]) >= 1
imp = await client.post(
"/api/v1/stickers/import",
json={**doc, "replace_duplicates": True},
)
assert imp.status == 200
data = await imp.json()
assert data.get("imported", 0) >= 1
@pytest.mark.asyncio
async def test_stickers_create_missing_image_bytes(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.post("/api/v1/stickers", json={"image_type": "png"})
assert r.status == 400
assert (await r.json()).get("error") == "missing_image_bytes"
@pytest.mark.asyncio
async def test_stickers_create_invalid_base64(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.post(
"/api/v1/stickers",
json={"image_type": "png", "image_bytes": "@@@not-valid-base64!!!"},
)
assert r.status == 400
assert (await r.json()).get("error") == "invalid_base64"
@pytest.mark.asyncio
async def test_stickers_create_bad_payload(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(b"not-a-png").decode("ascii")
async with TestClient(TestServer(aio_app)) as client:
r = await client.post(
"/api/v1/stickers",
json={"image_type": "png", "image_bytes": b64},
)
assert r.status == 400
assert "error" in await r.json()
@pytest.mark.asyncio
async def test_stickers_image_not_found(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.get("/api/v1/stickers/999999/image")
assert r.status == 404
@pytest.mark.asyncio
async def test_stickers_import_invalid_document(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.post(
"/api/v1/stickers/import",
json={"format": "wrong", "version": 1},
)
assert r.status == 400
body = await r.json()
assert "error" in body
@pytest.mark.asyncio
async def test_sticker_packs_create_list_get_delete(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
cr = await client.post(
"/api/v1/sticker-packs",
json={"title": " Pack One ", "pack_type": "static"},
)
assert cr.status == 200
pack = (await cr.json())["pack"]
pid = pack["id"]
ls = await client.get("/api/v1/sticker-packs")
assert ls.status == 200
packs = (await ls.json())["packs"]
assert any(p["id"] == pid for p in packs)
g = await client.get(f"/api/v1/sticker-packs/{pid}")
assert g.status == 200
assert (await g.json())["pack"]["id"] == pid
dl = await client.delete(f"/api/v1/sticker-packs/{pid}")
assert dl.status == 200
@pytest.mark.asyncio
async def test_sticker_packs_install_minimal(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(TINY_PNG).decode("ascii")
doc = {
"format": "meshchatx-stickerpack",
"version": 1,
"pack": {
"title": "Imported Pack",
"short_name": "imp",
"description": None,
"type": "static",
"author": None,
"is_strict": False,
},
"stickers": [
{"name": "a", "emoji": None, "image_type": "png", "image_bytes": b64},
],
}
async with TestClient(TestServer(aio_app)) as client:
r = await client.post("/api/v1/sticker-packs/install", json=doc)
assert r.status == 200
data = await r.json()
assert "pack" in data
assert data.get("imported", 0) >= 1
@pytest.mark.asyncio
async def test_sticker_packs_install_invalid(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.post(
"/api/v1/sticker-packs/install",
json={"format": "meshchatx-stickerpack", "version": 1},
)
assert r.status == 400
@pytest.mark.asyncio
async def test_gifs_create_get_image_use_export_import(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(TINY_GIF).decode("ascii")
async with TestClient(TestServer(aio_app)) as client:
c = await client.post(
"/api/v1/gifs",
json={"name": "g", "image_type": "gif", "image_bytes": b64},
)
assert c.status == 200
gid = (await c.json())["gif"]["id"]
img = await client.get(f"/api/v1/gifs/{gid}/image")
assert img.status == 200
assert "gif" in (img.headers.get("Content-Type") or "").lower()
assert await img.read() == TINY_GIF
u = await client.post(f"/api/v1/gifs/{gid}/use")
assert u.status == 200
ex = await client.get("/api/v1/gifs/export")
assert ex.status == 200
doc = await ex.json()
assert doc.get("format") == "meshchatx-gifs"
imp = await client.post(
"/api/v1/gifs/import",
json={**doc, "replace_duplicates": True},
)
assert imp.status == 200
assert (await imp.json()).get("imported", 0) >= 1
@pytest.mark.asyncio
async def test_gifs_create_missing_image_bytes(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.post("/api/v1/gifs", json={"image_type": "gif"})
assert r.status == 400
assert (await r.json()).get("error") == "missing_image_bytes"
@pytest.mark.asyncio
async def test_gifs_patch_requires_name(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(TINY_GIF).decode("ascii")
async with TestClient(TestServer(aio_app)) as client:
c = await client.post(
"/api/v1/gifs",
json={"image_type": "gif", "image_bytes": b64},
)
gid = (await c.json())["gif"]["id"]
r = await client.patch(f"/api/v1/gifs/{gid}", json={})
assert r.status == 400
assert (await r.json()).get("error") == "missing_name"
@pytest.mark.asyncio
async def test_gifs_image_not_found(web_media_app):
aio_app = _build_aio_app(web_media_app)
async with TestClient(TestServer(aio_app)) as client:
r = await client.get("/api/v1/gifs/999999/image")
assert r.status == 404
@pytest.mark.asyncio
async def test_stickers_strict_tgs_golden_bytes(web_media_app):
aio_app = _build_aio_app(web_media_app)
b64 = base64.b64encode(GZIP_TGS_512).decode("ascii")
async with TestClient(TestServer(aio_app)) as client:
r = await client.post(
"/api/v1/stickers",
json={
"name": "anim",
"image_type": "tgs",
"image_bytes": b64,
"strict": True,
},
)
assert r.status == 200
st = (await r.json())["sticker"]
assert st.get("image_type") == "tgs"