[Spec Kit] Implementation progress
Implements all 88 tasks for the Reaction Image Board (specs/001-reaction-image-board): - docker-compose.yml: postgres, minio, minio-init, api, ui services with healthchecks - api/: FastAPI app with SQLAlchemy 2.x async, Alembic migrations, S3/MinIO storage, full integration + unit test suite (pytest + pytest-asyncio) - ui/: Angular 19 standalone app (Library, Upload, Detail, NotFound components) - .env.example: all required environment variables - .gitignore: Python, Node, Docker, IDE, .env patterns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
60
api/tests/integration/test_search.py
Normal file
60
api/tests/integration/test_search.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
T041 — GET /api/v1/images?tags=cat,funny → only images with both tags
|
||||
T042 — same query excludes images with only one matching tag
|
||||
"""
|
||||
import io
|
||||
import pytest
|
||||
|
||||
|
||||
def _minimal_gif() -> bytes:
|
||||
return (
|
||||
b"GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00"
|
||||
b"!\xf9\x04\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01"
|
||||
b"\x00\x00\x02\x02D\x01\x00;"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_and_filter_returns_only_matching_images(client):
|
||||
data = _minimal_gif()
|
||||
|
||||
# Image with both tags
|
||||
r_both = await client.post(
|
||||
"/api/v1/images",
|
||||
files={"file": ("both.gif", io.BytesIO(data), "image/gif")},
|
||||
data={"tags": "andcat,andfunny"},
|
||||
)
|
||||
both_id = r_both.json()["id"]
|
||||
|
||||
# Image with only one of the two tags — use different content to avoid dedup
|
||||
r_one = await client.post(
|
||||
"/api/v1/images",
|
||||
files={"file": ("one.gif", io.BytesIO(data + b"\x00"), "image/gif")},
|
||||
data={"tags": "andcat"},
|
||||
)
|
||||
|
||||
response = await client.get("/api/v1/images?tags=andcat,andfunny")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
ids = [item["id"] for item in body["items"]]
|
||||
assert both_id in ids
|
||||
assert r_one.json()["id"] not in ids
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_filter_excludes_partial_tag_match(client):
|
||||
data = _minimal_gif()
|
||||
|
||||
# Image with only "exclcat"
|
||||
r_partial = await client.post(
|
||||
"/api/v1/images",
|
||||
files={"file": ("partial.gif", io.BytesIO(data + b"\x01"), "image/gif")},
|
||||
data={"tags": "exclcat"},
|
||||
)
|
||||
|
||||
# Filter requires both exclcat and exclother
|
||||
response = await client.get("/api/v1/images?tags=exclcat,exclother")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
ids = [item["id"] for item in body["items"]]
|
||||
assert r_partial.json()["id"] not in ids
|
||||
Reference in New Issue
Block a user