"""Tests for scan_library_for_rule Celery task. Eager mode is used so the task runs synchronously in-test and we can assert state via column selects (post-DML ORM access banned per reference-async-coredml-test-assertions).""" import pytest from PIL import Image from sqlalchemy import select import backend.app.tasks.library_audit # noqa: F401 — celery registration from backend.app import celery_app from backend.app.models import ImageRecord, LibraryAuditRun pytestmark = pytest.mark.integration def _mk_image(db_sync, tmp_path, *, mode, color, name): path = tmp_path / name Image.new(mode, (10, 10), color).save(path) # sha256 column is varchar(64) — pad/truncate a per-file pseudo hash # exactly to 64 chars. Each test fixture file must have a unique # sha256 (reference-image-record-path-unique peer constraint). sha = f"audit-{name}".ljust(64, "x")[:64] rec = ImageRecord( path=str(path), sha256=sha, size_bytes=path.stat().st_size, mime="image/png", width=10, height=10, origin="imported_filesystem", integrity_status="ok", ) db_sync.add(rec) db_sync.flush() return rec, path def test_scan_library_for_rule_populates_matched_ids_for_transparency( db_sync, tmp_path, monkeypatch, ): transparent_rec, _ = _mk_image( db_sync, tmp_path, mode="RGBA", color=(0, 0, 0, 0), name="trans.png", ) opaque_rec, _ = _mk_image( db_sync, tmp_path, mode="RGBA", color=(200, 0, 0, 255), name="opaque.png", ) audit = LibraryAuditRun( rule="transparency", params={"threshold": 0.5}, status="running", matched_ids=[], ) db_sync.add(audit) db_sync.commit() audit_id = audit.id monkeypatch.setattr(celery_app.celery.conf, "task_always_eager", True) from backend.app.tasks.library_audit import scan_library_for_rule scan_library_for_rule.run(audit_id) monkeypatch.setattr(celery_app.celery.conf, "task_always_eager", False) matched = db_sync.execute( select(LibraryAuditRun.matched_ids).where(LibraryAuditRun.id == audit_id) ).scalar_one() status = db_sync.execute( select(LibraryAuditRun.status).where(LibraryAuditRun.id == audit_id) ).scalar_one() assert transparent_rec.id in matched assert opaque_rec.id not in matched assert status == "ready" def test_scan_library_for_rule_skips_missing_files_gracefully( db_sync, tmp_path, monkeypatch, ): rec, path = _mk_image( db_sync, tmp_path, mode="RGBA", color=(0, 0, 0, 0), name="ghost.png", ) path.unlink() # delete the file but leave the DB row audit = LibraryAuditRun( rule="transparency", params={"threshold": 0.5}, status="running", matched_ids=[], ) db_sync.add(audit) db_sync.commit() audit_id = audit.id monkeypatch.setattr(celery_app.celery.conf, "task_always_eager", True) from backend.app.tasks.library_audit import scan_library_for_rule scan_library_for_rule.run(audit_id) monkeypatch.setattr(celery_app.celery.conf, "task_always_eager", False) status = db_sync.execute( select(LibraryAuditRun.status).where(LibraryAuditRun.id == audit_id) ).scalar_one() matched = db_sync.execute( select(LibraryAuditRun.matched_ids).where(LibraryAuditRun.id == audit_id) ).scalar_one() # Missing file is skipped (warning logged), audit completes successfully. assert status == "ready" assert rec.id not in matched