- conftest.py: pytest_configure guard rejects non-postgresql+asyncpg:// URLs before any test collects (per constitution §2.5/§5.2 v1.3.0) - docker-compose.test.yml: isolated postgres-test (5433) + minio-test (9002) + api-test runner; one command runs the full suite against real PostgreSQL - Makefile: test-unit and test-integration targets - .env.test.example: documents variables needed to run tests outside Docker - Fix pre-existing test bug: integration tests using client fixture (NoOpAuthProvider) for write operations (upload/delete/patch) now use authed_client with Bearer token — these were never caught because tests never ran against a live stack Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
"""
|
|
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(authed_client):
|
|
client, token = authed_client
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
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"},
|
|
headers=headers,
|
|
)
|
|
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"},
|
|
headers=headers,
|
|
)
|
|
|
|
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(authed_client):
|
|
client, token = authed_client
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
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"},
|
|
headers=headers,
|
|
)
|
|
|
|
# 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
|