feat: add workflow output comparison tooling
This commit is contained in:
@@ -4,6 +4,7 @@ import uuid
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from PIL import Image
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
@@ -545,3 +546,90 @@ async def test_workflow_dispatch_endpoint_returns_workflow_run_with_node_results
|
||||
assert node_results["template"]["status"] == "completed"
|
||||
assert node_results["template"]["output"]["use_materials"] is False
|
||||
assert node_results["output"]["status"] == "skipped"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workflow_run_comparison_endpoint_reports_identical_shadow_output(
|
||||
client,
|
||||
db,
|
||||
admin_user,
|
||||
auth_headers,
|
||||
tmp_path,
|
||||
):
|
||||
order_line = await _seed_renderable_order_line(db, admin_user, tmp_path)
|
||||
workflow_run = WorkflowRun(
|
||||
order_line_id=order_line.id,
|
||||
execution_mode="shadow",
|
||||
status="completed",
|
||||
)
|
||||
db.add(workflow_run)
|
||||
await db.flush()
|
||||
|
||||
render_dir = tmp_path / "comparison" / str(order_line.id)
|
||||
render_dir.mkdir(parents=True, exist_ok=True)
|
||||
authoritative_path = render_dir / "authoritative.png"
|
||||
shadow_path = render_dir / f"authoritative_shadow-{str(workflow_run.id)[:8]}.png"
|
||||
|
||||
Image.new("RGBA", (8, 8), (0, 128, 255, 255)).save(authoritative_path)
|
||||
Image.new("RGBA", (8, 8), (0, 128, 255, 255)).save(shadow_path)
|
||||
|
||||
order_line.result_path = str(authoritative_path)
|
||||
order_line.render_status = "completed"
|
||||
await db.commit()
|
||||
|
||||
response = await client.get(
|
||||
f"/api/workflows/runs/{workflow_run.id}/comparison",
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["workflow_run_id"] == str(workflow_run.id)
|
||||
assert body["execution_mode"] == "shadow"
|
||||
assert body["status"] == "matched"
|
||||
assert body["exact_match"] is True
|
||||
assert body["dimensions_match"] is True
|
||||
assert body["mean_pixel_delta"] == 0.0
|
||||
assert body["authoritative_output"]["path"] == str(authoritative_path)
|
||||
assert body["observer_output"]["path"] == str(shadow_path)
|
||||
assert body["authoritative_output"]["image_width"] == 8
|
||||
assert body["observer_output"]["image_height"] == 8
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workflow_run_comparison_endpoint_reports_missing_shadow_output(
|
||||
client,
|
||||
db,
|
||||
admin_user,
|
||||
auth_headers,
|
||||
tmp_path,
|
||||
):
|
||||
order_line = await _seed_renderable_order_line(db, admin_user, tmp_path)
|
||||
workflow_run = WorkflowRun(
|
||||
order_line_id=order_line.id,
|
||||
execution_mode="shadow",
|
||||
status="completed",
|
||||
)
|
||||
db.add(workflow_run)
|
||||
await db.flush()
|
||||
|
||||
render_dir = tmp_path / "comparison-missing" / str(order_line.id)
|
||||
render_dir.mkdir(parents=True, exist_ok=True)
|
||||
authoritative_path = render_dir / "authoritative.png"
|
||||
Image.new("RGBA", (4, 4), (255, 64, 64, 255)).save(authoritative_path)
|
||||
|
||||
order_line.result_path = str(authoritative_path)
|
||||
order_line.render_status = "completed"
|
||||
await db.commit()
|
||||
|
||||
response = await client.get(
|
||||
f"/api/workflows/runs/{workflow_run.id}/comparison",
|
||||
headers=auth_headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["status"] == "missing_observer"
|
||||
assert body["exact_match"] is None
|
||||
assert body["observer_output"]["exists"] is False
|
||||
assert body["authoritative_output"]["exists"] is True
|
||||
|
||||
Reference in New Issue
Block a user