22bc24b6b6
The CI failure resolving 'postgres' hostname was the symptom; the cause is that the workflow violated FabledRulebook/forgejo.md's "CI philosophy — lint + short unit tests only" rule. Integration tests against a real Postgres are supposed to run locally via docker-compose, not in CI. Changes: - Marked 8 DB-dependent test files with @pytest.mark.integration: test_tag_service, test_importer, test_gallery_service, test_api_gallery, test_api_tags, test_api_settings, test_api_import_admin, test_maintenance. - CI workflow drops the postgres/redis service containers and the alembic upgrade smoke step entirely. - Pytest invocation in CI changes to `pytest -v -m "not integration"`. - Added pytest marker registration to pyproject.toml. - DB_PASSWORD and SECRET_KEY env vars retained because config.py reads them at import time even though unit tests don't actually use them (set to placeholder values). What CI now runs: - ruff check - pytest on the 6 unit test files: test_slug, test_paths, test_migration_0002, test_thumbnailer, test_celery_smoke, test_tasks_register. - npm install + npm run build What CI no longer runs: - alembic upgrade (no live DB) - the 8 integration test files (these run locally via docker-compose) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
1.8 KiB
Python
73 lines
1.8 KiB
Python
from datetime import UTC, datetime, timedelta
|
|
|
|
import pytest
|
|
|
|
from backend.app import create_app
|
|
from backend.app.models import ImageRecord
|
|
|
|
pytestmark = pytest.mark.integration
|
|
|
|
|
|
@pytest.fixture
|
|
async def app():
|
|
return create_app()
|
|
|
|
|
|
@pytest.fixture
|
|
async def client(app):
|
|
async with app.test_client() as c:
|
|
yield c
|
|
|
|
|
|
async def _seed(db, count: int = 3):
|
|
base = datetime.now(UTC)
|
|
for i in range(count):
|
|
r = ImageRecord(
|
|
path=f"/images/x/{i}.jpg",
|
|
sha256=f"x{i:063d}",
|
|
size_bytes=1, mime="image/jpeg", width=1, height=1,
|
|
origin="imported_filesystem", integrity_status="unknown",
|
|
)
|
|
r.created_at = base - timedelta(minutes=i)
|
|
db.add(r)
|
|
await db.flush()
|
|
await db.commit()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_scroll_returns_images(client, db):
|
|
await _seed(db)
|
|
resp = await client.get("/api/gallery/scroll?limit=10")
|
|
assert resp.status_code == 200
|
|
body = await resp.get_json()
|
|
assert len(body["images"]) == 3
|
|
assert "next_cursor" in body
|
|
assert "date_groups" in body
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_scroll_rejects_bad_limit(client):
|
|
resp = await client.get("/api/gallery/scroll?limit=notanumber")
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_timeline_endpoint(client, db):
|
|
await _seed(db)
|
|
resp = await client.get("/api/gallery/timeline")
|
|
assert resp.status_code == 200
|
|
body = await resp.get_json()
|
|
assert sum(b["count"] for b in body) == 3
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_jump_requires_year_month(client):
|
|
resp = await client.get("/api/gallery/jump")
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_detail_404_when_missing(client):
|
|
resp = await client.get("/api/gallery/image/99999")
|
|
assert resp.status_code == 404
|