feat: extract workflow output save phase 3
This commit is contained in:
@@ -5,7 +5,7 @@ import uuid
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine, text
|
||||
from sqlalchemy import create_engine, select, text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import Base
|
||||
@@ -17,6 +17,7 @@ from app.domains.products.models import CadFile, Product
|
||||
from app.domains.rendering.models import OutputType, RenderTemplate
|
||||
from app.domains.rendering.workflow_runtime_services import (
|
||||
auto_populate_materials_for_cad,
|
||||
persist_order_line_output,
|
||||
resolve_cad_bbox,
|
||||
prepare_order_line_render_context,
|
||||
resolve_order_line_material_map,
|
||||
@@ -431,3 +432,114 @@ def test_extract_metadata_bbox_wrappers_delegate_to_runtime_services(monkeypatch
|
||||
assert _bbox_from_step_cadquery("/tmp/a.step") == {
|
||||
"dimensions_mm": {"x": 4.0, "y": 5.0, "z": 6.0}
|
||||
}
|
||||
|
||||
|
||||
def test_persist_order_line_output_saves_success_and_creates_media_asset(sync_session, tmp_path, monkeypatch):
|
||||
from app.config import settings
|
||||
|
||||
upload_dir = tmp_path / "uploads"
|
||||
monkeypatch.setattr(settings, "upload_dir", str(upload_dir))
|
||||
line = _seed_order_line_graph(sync_session, tmp_path)
|
||||
output_path = upload_dir / "renders" / str(line.id) / "bearing.png"
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text("PNGDATA", encoding="utf-8")
|
||||
|
||||
result = persist_order_line_output(
|
||||
sync_session,
|
||||
line,
|
||||
success=True,
|
||||
output_path=str(output_path),
|
||||
render_log={
|
||||
"renderer": "blender",
|
||||
"engine": "cycles",
|
||||
"engine_used": "cycles",
|
||||
"samples": 64,
|
||||
"total_duration_s": 1.23,
|
||||
},
|
||||
)
|
||||
|
||||
sync_session.refresh(line)
|
||||
asset = sync_session.execute(
|
||||
select(MediaAsset).where(MediaAsset.order_line_id == line.id)
|
||||
).scalar_one_or_none()
|
||||
|
||||
assert result.status == "completed"
|
||||
assert result.result_path == str(output_path)
|
||||
assert result.storage_key == f"renders/{line.id}/bearing.png"
|
||||
assert result.asset_type == MediaAssetType.still
|
||||
assert line.render_status == "completed"
|
||||
assert line.result_path == str(output_path)
|
||||
assert asset is not None
|
||||
assert asset.storage_key == f"renders/{line.id}/bearing.png"
|
||||
assert asset.asset_type == MediaAssetType.still
|
||||
assert asset.file_size_bytes == output_path.stat().st_size
|
||||
assert asset.mime_type == "image/png"
|
||||
assert asset.render_config == {
|
||||
"renderer": "blender",
|
||||
"engine": "cycles",
|
||||
"engine_used": "cycles",
|
||||
"samples": 64,
|
||||
"total_duration_s": 1.23,
|
||||
}
|
||||
|
||||
|
||||
def test_persist_order_line_output_reuses_existing_asset(sync_session, tmp_path, monkeypatch):
|
||||
from app.config import settings
|
||||
|
||||
upload_dir = tmp_path / "uploads"
|
||||
monkeypatch.setattr(settings, "upload_dir", str(upload_dir))
|
||||
line = _seed_order_line_graph(sync_session, tmp_path)
|
||||
output_path = upload_dir / "renders" / str(line.id) / "bearing.mp4"
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text("MP4DATA", encoding="utf-8")
|
||||
|
||||
existing = MediaAsset(
|
||||
id=uuid.uuid4(),
|
||||
order_line_id=line.id,
|
||||
product_id=line.product_id,
|
||||
asset_type=MediaAssetType.turntable,
|
||||
storage_key=f"renders/{line.id}/bearing.mp4",
|
||||
)
|
||||
sync_session.add(existing)
|
||||
sync_session.commit()
|
||||
|
||||
result = persist_order_line_output(
|
||||
sync_session,
|
||||
line,
|
||||
success=True,
|
||||
output_path=str(output_path),
|
||||
render_log={"renderer": "blender"},
|
||||
)
|
||||
|
||||
assets = sync_session.execute(
|
||||
select(MediaAsset).where(MediaAsset.storage_key == f"renders/{line.id}/bearing.mp4")
|
||||
).scalars().all()
|
||||
|
||||
assert result.asset_id == str(existing.id)
|
||||
assert result.asset_type == MediaAssetType.turntable
|
||||
assert len(assets) == 1
|
||||
|
||||
|
||||
def test_persist_order_line_output_marks_failure_without_result_path(sync_session, tmp_path):
|
||||
line = _seed_order_line_graph(sync_session, tmp_path)
|
||||
|
||||
result = persist_order_line_output(
|
||||
sync_session,
|
||||
line,
|
||||
success=False,
|
||||
output_path=str(tmp_path / "renders" / "failed.png"),
|
||||
render_log={"error": "boom"},
|
||||
)
|
||||
|
||||
sync_session.refresh(line)
|
||||
assets = sync_session.execute(
|
||||
select(MediaAsset).where(MediaAsset.order_line_id == line.id)
|
||||
).scalars().all()
|
||||
|
||||
assert result.status == "failed"
|
||||
assert result.result_path is None
|
||||
assert result.asset_id is None
|
||||
assert line.render_status == "failed"
|
||||
assert line.result_path is None
|
||||
assert line.render_log == {"error": "boom"}
|
||||
assert assets == []
|
||||
|
||||
Reference in New Issue
Block a user