"""Tests for how _build_asset_response derives the response `loader_path`. Guards the persist-and-read contract: the response reads the stored `loader_path` directly, and only recomputes when the column is NULL (rows written before the column existed). """ from datetime import datetime from pathlib import Path from unittest.mock import patch from app.assets.api.routes import _build_asset_response from app.assets.services.schemas import AssetDetailResult, ReferenceData _TS = datetime(2024, 1, 1, 0, 0, 0) def _make_result( *, file_path: str | None, loader_path: str | None ) -> AssetDetailResult: ref = ReferenceData( id="ref-1", name="model.safetensors", file_path=file_path, loader_path=loader_path, user_metadata=None, preview_id=None, created_at=_TS, updated_at=_TS, last_access_time=_TS, ) return AssetDetailResult(ref=ref, asset=None, tags=[]) def test_uses_persisted_loader_path_without_recomputing(): """A stored loader_path is returned verbatim, not re-derived from file_path. The sentinel value could never be produced by compute_loader_path for this file_path, so seeing it in the response proves the stored column is read. """ result = _make_result( file_path="/unmatched/root/model.safetensors", loader_path="SENTINEL/stored.safetensors", ) resp = _build_asset_response(result) assert resp.loader_path == "SENTINEL/stored.safetensors" def test_falls_back_to_compute_when_stored_loader_path_is_null(tmp_path: Path): """A NULL column (pre-migration row) is backfilled at read time.""" models = tmp_path / "models" ckpt = models / "checkpoints" ckpt.mkdir(parents=True) f = ckpt / "bar.safetensors" f.touch() with patch("app.assets.services.path_utils.folder_paths") as mock_fp, patch( "app.assets.services.path_utils.get_comfy_models_folders", return_value=[("checkpoints", [str(ckpt)], {".safetensors"})], ): mock_fp.get_input_directory.return_value = str(tmp_path / "in") mock_fp.get_output_directory.return_value = str(tmp_path / "out") mock_fp.get_temp_directory.return_value = str(tmp_path / "tmp") mock_fp.models_dir = str(models) result = _make_result(file_path=str(f), loader_path=None) resp = _build_asset_response(result) assert resp.loader_path == "bar.safetensors" assert resp.display_name == "checkpoints/bar.safetensors" def test_all_path_fields_null_without_file_path(): """API-created / hash-only references (no file_path) expose no paths.""" result = _make_result(file_path=None, loader_path=None) resp = _build_asset_response(result) assert resp.loader_path is None assert resp.display_name is None