Files
malkuthro-ComfyUI-Koolook/tests/server/test_published_setup_runner.py
T

173 lines
6.3 KiB
Python

from __future__ import annotations
import asyncio
from copy import deepcopy
import pytest
from koolook_setup_runner import PublishedSetupRunner, SetupRunError
from koolook_setups import PublishedSetupRegistry, StaticSetupStorage
from tests.server.test_published_setup_registry import _valid_setup
class FakeComfyClient:
def __init__(self, prompt_response=None, *, history=None, queue=None, queue_error=None) -> None:
self.prompt_response = prompt_response or {"prompt_id": "comfy-prompt-1"}
self.submitted_prompts: list[dict] = []
self.history = history or {}
self.queue = queue or {"queue_running": [], "queue_pending": []}
self.queue_error = queue_error
async def queue_prompt(self, prompt: dict) -> dict:
if self.queue_error is not None:
raise self.queue_error
self.submitted_prompts.append(prompt)
return self.prompt_response
async def get_history(self, prompt_id: str) -> dict:
return {prompt_id: self.history[prompt_id]} if prompt_id in self.history else {}
async def get_queue(self) -> dict:
return self.queue
def test_run_setup_injects_declared_inputs_into_cloned_prompt() -> None:
async def exercise() -> None:
setup = _valid_setup()
original_prompt = deepcopy(setup["apiPrompt"])
registry = PublishedSetupRegistry(StaticSetupStorage([setup]))
comfy = FakeComfyClient()
runner = PublishedSetupRunner(registry, comfy)
result = await runner.runSetup("ltx-director-demo", {"prompt": "external prompt"})
assert result == {
"runId": "run-000001",
"promptId": "comfy-prompt-1",
"status": "queued",
}
assert comfy.submitted_prompts == [
{"12": {"class_type": "Text Multiline", "inputs": {"text": "external prompt"}}}
]
assert setup["apiPrompt"] == original_prompt
asyncio.run(exercise())
def test_run_setup_rejects_inputs_not_declared_by_contract() -> None:
async def exercise() -> None:
registry = PublishedSetupRegistry(StaticSetupStorage([_valid_setup()]))
runner = PublishedSetupRunner(registry, FakeComfyClient())
with pytest.raises(SetupRunError) as exc_info:
await runner.runSetup("ltx-director-demo", {"prompt": "ok", "seed": 123})
assert exc_info.value.status_code == 400
assert exc_info.value.errors == ["input 'seed' is not declared by this setup"]
asyncio.run(exercise())
def test_run_setup_rejects_non_callable_setup() -> None:
async def exercise() -> None:
setup = _valid_setup()
setup["apiPrompt"] = None
setup["validation"] = {"status": "draft", "diagnostics": ["API prompt conversion pending."]}
registry = PublishedSetupRegistry(StaticSetupStorage([setup]))
runner = PublishedSetupRunner(registry, FakeComfyClient())
with pytest.raises(SetupRunError) as exc_info:
await runner.runSetup("ltx-director-demo", {"prompt": "external prompt"})
assert exc_info.value.status_code == 400
assert exc_info.value.errors == ["Published setup 'ltx-director-demo' is not callable."]
asyncio.run(exercise())
def test_run_setup_translates_comfy_queue_failures() -> None:
async def exercise() -> None:
registry = PublishedSetupRegistry(StaticSetupStorage([_valid_setup()]))
runner = PublishedSetupRunner(registry, FakeComfyClient(queue_error=RuntimeError("server down")))
with pytest.raises(SetupRunError) as exc_info:
await runner.runSetup("ltx-director-demo", {"prompt": "external prompt"})
assert exc_info.value.status_code == 502
assert exc_info.value.errors == ["ComfyUI queue request failed: server down"]
asyncio.run(exercise())
def test_get_run_reports_running_state_from_comfy_queue() -> None:
async def exercise() -> None:
registry = PublishedSetupRegistry(StaticSetupStorage([_valid_setup()]))
runner = PublishedSetupRunner(
registry,
FakeComfyClient(queue={"queue_running": [[7, "comfy-prompt-1", {}]], "queue_pending": []}),
)
queued = await runner.runSetup("ltx-director-demo", {"prompt": "external prompt"})
status = await runner.getRun(queued["runId"])
assert status == {
"runId": "run-000001",
"setupId": "ltx-director-demo",
"promptId": "comfy-prompt-1",
"status": "running",
"outputs": [],
}
asyncio.run(exercise())
def test_run_setup_accepts_inputs_declared_by_app_surface_contract() -> None:
async def exercise() -> None:
setup = _valid_setup()
setup["inputContract"] = {"inputs": []}
setup["outputContract"] = {"outputs": []}
setup["visualGraph"]["groups"] = [
{"title": "Koolook Input", "bounding": [0, 0, 300, 200]},
{"title": "Koolook Output", "bounding": [400, 0, 300, 200]},
]
setup["visualGraph"]["nodes"][0]["pos"] = [20, 20]
setup["setupSurface"] = {
"sourceInputs": [
{
"group": "Koolook Input",
"nodes": [{"id": "12", "type": "Text Multiline", "title": "Prompt"}],
}
],
"outputs": [
{
"group": "Koolook Output",
"nodes": [{"id": "20", "type": "Preview Image", "title": "Preview"}],
}
],
"controls": [],
"app": {
"inputs": [
{
"key": "prompt",
"label": "Prompt",
"visible": True,
"target": {"node": "12", "input": "text"},
"default": "demo prompt",
}
],
"outputs": [],
"results": [],
},
}
registry = PublishedSetupRegistry(StaticSetupStorage([setup]))
comfy = FakeComfyClient()
runner = PublishedSetupRunner(registry, comfy)
await runner.runSetup("ltx-director-demo", {"prompt": "app contract prompt"})
assert comfy.submitted_prompts == [
{"12": {"class_type": "Text Multiline", "inputs": {"text": "app contract prompt"}}}
]
asyncio.run(exercise())