verifile-x-api / backend /tests /test_monitoring.py
abinazebinoy's picture
fix(ci): fix 10 test failures from previous commits
f7ee01f
Raw
History Blame Contribute Delete
6.11 kB
"""
Tests for Phase 16: observability, inconclusive verdict, image type classifier.
"""
import numpy as np
from PIL import Image
from io import BytesIO
def _make_image(width=128, height=128, seed=42, fmt="JPEG"):
rng = np.random.default_rng(seed)
arr = rng.integers(30, 220, (height, width, 3), dtype=np.uint8)
buf = BytesIO()
Image.fromarray(arr, "RGB").save(buf, format=fmt, quality=85 if fmt=="JPEG" else None)
return buf.getvalue()
def _make_blank():
arr = np.zeros((128, 128, 3), dtype=np.uint8)
buf = BytesIO()
Image.fromarray(arr, "RGB").save(buf, format="PNG")
return buf.getvalue()
# ── Image type classifier ──────────────────────────────────────────────────────
def test_classifier_returns_valid_type():
from backend.services.image_type_classifier import classify_image_type
result = classify_image_type(_make_image(), "test.jpg")
assert result["image_type"] in {"photo", "screenshot_ui", "illustration",
"document", "low_info", "unknown"}
def test_classifier_blank_is_low_info():
from backend.services.image_type_classifier import classify_image_type
result = classify_image_type(_make_blank(), "blank.png")
assert result["image_type"] == "low_info"
assert result["run_prnu"] is False
assert result["run_ela"] is False
def test_classifier_jpeg_photo():
from backend.services.image_type_classifier import classify_image_type
result = classify_image_type(_make_image(256, 256, fmt="JPEG"), "photo.jpg")
assert result["image_type"] in {"photo", "unknown"}
assert 0.0 <= result["confidence"] <= 1.0
def test_classifier_corrupt_safe():
from backend.services.image_type_classifier import classify_image_type
result = classify_image_type(b"corrupt", "bad.jpg")
assert result["image_type"] == "unknown"
def test_classifier_all_fields_present():
from backend.services.image_type_classifier import classify_image_type
result = classify_image_type(_make_image(), "test.jpg")
for key in ("image_type", "confidence", "is_photo", "run_prnu",
"run_ela", "run_metadata", "explanation"):
assert key in result
# ── Metrics collector ─────────────────────────────────────────────────────────
def test_metrics_initial_state():
from backend.services.metrics_collector import get_metrics, reset_metrics
reset_metrics()
m = get_metrics()
assert m["requests"]["total_in_window"] == 0
assert m["detection"]["n_scored"] == 0
def test_metrics_record_analysis():
from backend.services.metrics_collector import record_analysis, get_metrics, reset_metrics
reset_metrics()
record_analysis(
ai_probability=0.85,
classification="likely_ai_generated",
latency_ms=250.0,
predicted_generator="stylegan",
platform_origin="instagram",
signal_scores=[{"signal_name": "FFT Radial Spectrum", "score": 0.7}],
)
m = get_metrics()
assert m["requests"]["total_in_window"] == 1
assert m["detection"]["n_scored"] == 1
assert m["detection"]["mean_ai_probability"] == 0.85
assert "likely_ai_generated" in m["classification_breakdown"]
assert m["classification_breakdown"]["likely_ai_generated"] == 1
def test_metrics_error_recording():
from backend.services.metrics_collector import record_analysis, get_metrics, reset_metrics
reset_metrics()
record_analysis(ai_probability=0.0, classification="error",
latency_ms=0.0, error=True)
m = get_metrics()
assert m["requests"]["errors_in_window"] == 1
assert m["requests"]["error_rate"] == 1.0
def test_metrics_reset():
from backend.services.metrics_collector import record_analysis, reset_metrics, get_metrics
record_analysis(0.5, "unknown", 100.0)
reset_metrics()
m = get_metrics()
assert m["requests"]["total_in_window"] == 0
def test_metrics_endpoint(client):
response = client.get("/api/v1/metrics")
assert response.status_code == 200
data = response.json()
assert "uptime_seconds" in data
assert "requests" in data
assert "detection" in data
assert "performance" in data
def test_metrics_reset_endpoint(client):
response = client.post("/api/v1/metrics/reset",
headers={"X-Admin-Key": "test-admin-key-12345"})
assert response.status_code == 200
assert "reset" in response.json()["message"].lower()
# ── Inconclusive verdict ──────────────────────────────────────────────────────
def test_inconclusive_appears_in_valid_labels():
"""Classification must include inconclusive as a valid label."""
valid = {"likely_ai_generated", "possibly_ai_generated",
"possibly_authentic", "likely_authentic", "inconclusive"}
from backend.services.advanced_ensemble_detector import AdvancedEnsembleDetector
det = AdvancedEnsembleDetector(_make_image(), "test.jpg")
r = det.detect()
det.cleanup()
assert r["classification"] in valid
# ── Image type in forensic report ────────────────────────────────────────────
def test_image_type_in_forensic_report():
from backend.services.image_forensics import ImageForensics
rng = np.random.default_rng(seed=5555)
arr = rng.integers(30, 220, (128, 128, 3), dtype=np.uint8)
buf = BytesIO()
Image.fromarray(arr, "RGB").save(buf, format="PNG")
report = ImageForensics(buf.getvalue(), "type_test.png").generate_forensic_report()
assert "image_type" in report
assert report["image_type"]["image_type"] in {
"photo", "screenshot_ui", "illustration", "document", "low_info", "unknown"
}
assert "image_type" in report["summary"]