Old project/workflow names and browser settings migrate on load; /funpack redirects to /fun. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016acRss69eH1235eRdFTZHY
85 lines
4.2 KiB
Python
85 lines
4.2 KiB
Python
from core import readiness as r
|
|
|
|
|
|
def levels(rows):
|
|
return [x["level"] for x in rows]
|
|
|
|
|
|
def test_no_model_files_is_a_failure_and_empty_folders_are_named():
|
|
rows = r.models({"diffusion_models": 0, "checkpoints": 0, "vae": 2})
|
|
assert rows[0]["level"] == "fail" and "No model files" in rows[0]["text"]
|
|
assert any("No diffusion models" in x["text"] for x in rows) and any(x["text"] == "2 VAEs" for x in rows)
|
|
assert "fail" not in levels(r.models({"diffusion_models": 1}))
|
|
|
|
|
|
def test_a_preset_naming_a_node_that_is_not_installed_says_which_and_where_to_get_it():
|
|
presets = [{"id": "a", "title": "H3", "slots": [{"node": "Have"}, {"node": "ImageTransformKJ"}]}, {"id": "b", "slots": [{"node": "Have"}]}]
|
|
rows = r.pipelines(presets, lambda cls: cls == "Have")
|
|
assert len(rows) == 1 and "ImageTransformKJ" in rows[0]["text"] and "H3" in rows[0]["text"]
|
|
assert r.pipelines(presets[1:], lambda cls: True)[0]["level"] == "ok"
|
|
|
|
|
|
def test_modules_that_failed_or_are_switched_off_are_listed():
|
|
rows = r.modules([("modules.x", "ImportError: nope")], {"reins": {"reason": "boom"}})
|
|
assert len(rows) == 2 and "nope" in rows[0]["text"] and "reins" in rows[1]["text"]
|
|
assert r.modules([], {})[0]["level"] == "ok"
|
|
|
|
|
|
def test_the_machine_checks_never_raise_and_low_disk_is_a_warning(monkeypatch):
|
|
monkeypatch.setattr(r.shutil, "which", lambda name: None)
|
|
rows = r.machine(disk_free_gb=3)
|
|
assert any(x["level"] == "fail" and "ffmpeg" in x["text"] for x in rows)
|
|
assert any(x["level"] == "warn" and "3 GB free" in x["text"] for x in rows)
|
|
|
|
|
|
def test_the_row_names_the_device_comfyui_generates_on(monkeypatch):
|
|
monkeypatch.setattr(r, "device", lambda: "mps")
|
|
rows = r.machine()
|
|
assert any(x["level"] == "ok" and "MPS" in x["text"] for x in rows)
|
|
assert not any("sageattention" in x["text"] for x in rows) # a CUDA-only library
|
|
monkeypatch.setattr(r, "device", lambda: "cpu") # ComfyUI started with --cpu, GPU or not
|
|
assert any(x["level"] == "warn" and "on the CPU" in x["text"] for x in r.machine())
|
|
monkeypatch.setattr(r, "device", lambda: "xpu") # an Intel GPU is not the CPU
|
|
rows = r.machine()
|
|
assert any("'xpu'" in x["text"] for x in rows) and not any("on the CPU" in x["text"] for x in rows)
|
|
|
|
|
|
def test_the_gpu_row_names_the_card_comfyui_uses(monkeypatch):
|
|
import types
|
|
import torch
|
|
asked = []
|
|
monkeypatch.setattr(r, "device", lambda: "cuda")
|
|
monkeypatch.setattr(r, "gpu_index", lambda: 1)
|
|
monkeypatch.setattr(torch.cuda, "get_device_properties",
|
|
lambda i: asked.append(i) or types.SimpleNamespace(name=f"GPU{i}", total_memory=32 * 1024 ** 3, major=12, minor=0))
|
|
rows = r.machine()
|
|
assert asked == [1] and any("GPU1" in x["text"] for x in rows)
|
|
|
|
|
|
def test_the_blackwell_xformers_warning_follows_whether_xformers_is_on_not_installed(monkeypatch):
|
|
import types
|
|
import torch
|
|
monkeypatch.setattr(r, "device", lambda: "cuda")
|
|
monkeypatch.setattr(r, "gpu_index", lambda: 0)
|
|
monkeypatch.setattr(torch.cuda, "get_device_properties",
|
|
lambda i: types.SimpleNamespace(name="B", total_memory=96 * 1024 ** 3, major=12, minor=0))
|
|
for on, warned in ((True, True), (False, False)):
|
|
monkeypatch.setattr(r, "xformers_on", lambda: on)
|
|
assert any("xformers" in x["text"] for x in r.machine()) is warned
|
|
|
|
|
|
def test_a_funui_node_that_is_missing_points_at_the_modules_page_not_at_another_pack():
|
|
from core import readiness
|
|
rows = readiness.pipelines([{"id": "p", "title": "P", "slots": [{"node": "FunUICutOpening"}, {"node": "ImageTransformKJ"}]}],
|
|
installed=lambda n: False)
|
|
text = " | ".join(r["text"] for r in rows)
|
|
assert "FunUICutOpening" in text and "not available" in text
|
|
assert "ImageTransformKJ" in text and "Custom Nodes" in text
|
|
|
|
|
|
def test_a_missing_optional_node_is_not_a_need():
|
|
from core import readiness
|
|
rows = readiness.pipelines([{"id": "p", "title": "P", "slots": [{"node": "FunUICutOpening"}]}],
|
|
installed=lambda n: False, optional={"FunUICutOpening"})
|
|
assert [r["level"] for r in rows] == ["ok"] and "runs without FunUICutOpening" in rows[0]["text"]
|