Files
ComfyUI-OpenClaw/tests/test_r167_asset_api_contract.py
rookiestar28 886e91c491 fix(outputs): make asset hashes optional
Keep filename-backed output references previewable when hosts omit hash metadata, while preserving the explicit no-go path for asset-only references.

Update public docs and generated OpenAPI contract to describe optional hash metadata and the ComfyUI asset hashing flag.

Validation: targeted backend/unit/E2E checks passed; full Windows test gate passed.
2026-07-08 02:58:39 +08:00

101 lines
3.6 KiB
Python

import unittest
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch
class TestR167AssetApiContract(unittest.IsolatedAsyncioTestCase):
def test_asset_api_decision_doc_tracks_current_feature_gated_surface(self):
doc = (
Path(__file__).resolve().parents[1]
/ "docs"
/ "asset_api_adoption_decision.md"
).read_text(encoding="utf-8")
self.assertIn("/api/assets", doc)
self.assertIn("--enable-assets", doc)
self.assertIn("--enable-asset-hashing", doc)
self.assertIn("optional", doc.lower())
self.assertIn("/features", doc)
self.assertIn("blake3", doc)
self.assertIn("/view", doc)
def test_public_output_ref_docs_state_hashes_are_optional(self):
repo_root = Path(__file__).resolve().parents[1]
public_docs = [
repo_root / "README.md",
repo_root / "docs" / "release" / "api_contract.md",
repo_root / "docs" / "troubleshooting.md",
repo_root / "docs" / "frontend_ux_walkthrough.md",
]
for doc_path in public_docs:
with self.subTest(doc=str(doc_path.relative_to(repo_root))):
doc = doc_path.read_text(encoding="utf-8").lower()
self.assertIn("optional", doc)
self.assertIn("/view", doc)
self.assertIn("hash", doc)
async def test_callback_delivery_preserves_asset_api_only_refs_without_view_fetch(
self,
):
import services.callback_delivery as callback_delivery
sent_payloads = []
history_item = {
"outputs": {
"3": {
"images": [
{
"asset": {
"id": "asset-only-42",
}
}
]
}
}
}
async def fake_run_io(func, *args, **kwargs):
if func is callback_delivery.fetch_history:
return history_item
if func is callback_delivery.safe_request_json:
sent_payloads.append(args[2])
return {"ok": True}
raise AssertionError(f"unexpected func: {func}")
with (
patch.object(
callback_delivery, "run_io_in_thread", side_effect=fake_run_io
),
patch.object(
callback_delivery.asyncio, "sleep", AsyncMock(return_value=None)
),
patch.object(
callback_delivery,
"get_callback_allow_hosts",
return_value={"example.com"},
),
patch.object(callback_delivery, "get_job_status", return_value="completed"),
patch.object(
callback_delivery, "get_job_event_store", return_value=MagicMock()
),
patch.object(callback_delivery.trace_store, "add_event", return_value=None),
):
await callback_delivery._watch_and_deliver(
"p-r167",
{"url": "https://example.com/hook"},
trace_id="trace-r167",
)
self.assertEqual(len(sent_payloads), 1)
outputs = sent_payloads[0]["outputs"]
self.assertEqual(len(outputs), 1)
self.assertEqual(outputs[0]["asset_api_id"], "asset-only-42")
self.assertTrue(outputs[0]["asset_api_required"])
self.assertEqual(outputs[0]["resolution"], "asset_api_required")
self.assertEqual(outputs[0]["view_url"], "")
if __name__ == "__main__":
unittest.main()