Files
HartOMat/backend/tests/domains/test_rendering_publish_asset.py
T

153 lines
4.7 KiB
Python

from __future__ import annotations
import os
import uuid
from contextlib import contextmanager
from pathlib import Path
import pytest
from sqlalchemy import select, text
from sqlalchemy.orm import Session
from app.domains.auth.models import User, UserRole
from app.domains.media.models import MediaAsset, MediaAssetType
from app.domains.orders.models import Order, OrderLine, OrderStatus
from app.domains.products.models import CadFile, Product
from app.domains.rendering.models import OutputType
from tests.db_test_utils import sync_test_session as sync_test_session_ctx
@pytest.fixture
def sync_session():
with sync_test_session_ctx() as session:
yield session
def _seed_order_line(session: Session, tmp_path: Path) -> OrderLine:
step_path = tmp_path / "parts" / "bearing.step"
step_path.parent.mkdir(parents=True, exist_ok=True)
step_path.write_text("STEP", encoding="utf-8")
user = User(
id=uuid.uuid4(),
email=f"publish-{uuid.uuid4().hex[:8]}@test.local",
password_hash="hash",
full_name="Publish Tester",
role=UserRole.admin,
is_active=True,
)
cad_file = CadFile(
id=uuid.uuid4(),
original_name="bearing.step",
stored_path=str(step_path),
file_hash=f"hash-{uuid.uuid4().hex}",
)
product = Product(
id=uuid.uuid4(),
pim_id="P-2000",
name="Bearing Publish",
category_key="bearings",
cad_file_id=cad_file.id,
cad_file=cad_file,
)
output_type = OutputType(
id=uuid.uuid4(),
name="HQ Still",
renderer="blender",
output_format="png",
render_settings={"width": 1600, "height": 900},
)
order = Order(
id=uuid.uuid4(),
order_number=f"ORD-{uuid.uuid4().hex[:8]}",
status=OrderStatus.processing,
created_by=user.id,
)
line = OrderLine(
id=uuid.uuid4(),
order_id=order.id,
product_id=product.id,
product=product,
output_type_id=output_type.id,
output_type=output_type,
render_status="processing",
)
session.add_all([user, cad_file, product, output_type, order, line])
session.commit()
return line
def test_publish_asset_canonicalizes_still_outputs(sync_session, tmp_path, monkeypatch):
from app.config import settings
from app.domains.rendering.tasks import publish_asset
upload_dir = tmp_path / "uploads"
monkeypatch.setattr(settings, "upload_dir", str(upload_dir))
line = _seed_order_line(sync_session, tmp_path)
source_output = tmp_path / "parts" / "renders" / "line.png"
source_output.parent.mkdir(parents=True, exist_ok=True)
source_output.write_bytes(b"png")
@contextmanager
def _session_ctx():
yield sync_session
monkeypatch.setattr("app.core.db_utils.get_sync_session", _session_ctx)
asset_id = publish_asset.run(
str(line.id),
"still",
str(source_output),
render_config={"renderer": "blender", "engine_used": "cycles"},
)
sync_session.expire_all()
stored_line = sync_session.get(OrderLine, line.id)
stored_asset = sync_session.execute(
select(MediaAsset).where(MediaAsset.id == uuid.UUID(asset_id))
).scalar_one()
assert stored_line.result_path == f"{upload_dir}/renders/{line.id}/Bearing_Publish_HQ_Still.png"
assert Path(stored_line.result_path).is_file()
assert stored_asset.storage_key == f"renders/{line.id}/Bearing_Publish_HQ_Still.png"
assert stored_asset.asset_type == MediaAssetType.still
def test_publish_asset_canonicalizes_blend_storage_key_without_touching_order_line(sync_session, tmp_path, monkeypatch):
from app.config import settings
from app.domains.rendering.tasks import publish_asset
upload_dir = tmp_path / "uploads"
monkeypatch.setattr(settings, "upload_dir", str(upload_dir))
line = _seed_order_line(sync_session, tmp_path)
source_output = tmp_path / "parts" / "bearing_production.blend"
source_output.parent.mkdir(parents=True, exist_ok=True)
source_output.write_bytes(b"blend")
@contextmanager
def _session_ctx():
yield sync_session
monkeypatch.setattr("app.core.db_utils.get_sync_session", _session_ctx)
asset_id = publish_asset.run(
str(line.id),
"blend_production",
str(source_output),
render_config={"artifact_type": "blend_production"},
)
sync_session.expire_all()
stored_line = sync_session.get(OrderLine, line.id)
stored_asset = sync_session.execute(
select(MediaAsset).where(MediaAsset.id == uuid.UUID(asset_id))
).scalar_one()
assert stored_line.result_path is None
assert stored_asset.storage_key == str(source_output)
assert stored_asset.asset_type == MediaAssetType.blend_production