"""Tests for the Random Checkpoint/Unet Loader nodes' base-model filtering and random-selection behavior. """ import pytest from py.nodes.random_checkpoint_loader import RandomCheckpointLoaderLM from py.nodes.random_unet_loader import RandomUNETLoaderLM class _FakeCache: def __init__(self, raw_data): self.raw_data = raw_data class _FakeScanner: def __init__(self, raw_data, model_roots): self._raw_data = raw_data self._model_roots = model_roots async def get_cached_data(self, force_refresh=False): return _FakeCache(self._raw_data) def get_model_roots(self): return self._model_roots @pytest.fixture def base_model_library(tmp_path, monkeypatch): from py.services.service_registry import ServiceRegistry illustrious = tmp_path / "illustrious.safetensors" illustrious.write_bytes(b"x") flux = tmp_path / "flux.safetensors" flux.write_bytes(b"x") missing = tmp_path / "missing.safetensors" # referenced but never created raw_data = [ { "sub_type": "checkpoint", "file_path": str(illustrious), "base_model": "Illustrious", }, {"sub_type": "checkpoint", "file_path": str(flux), "base_model": "Flux.1 D"}, { "sub_type": "checkpoint", "file_path": str(missing), "base_model": "SDXL 1.0", }, { "sub_type": "diffusion_model", "file_path": str(flux), "base_model": "Flux.1 D", }, ] async def _fake_scanner(): return _FakeScanner(raw_data, [str(tmp_path)]) monkeypatch.setattr(ServiceRegistry, "get_checkpoint_scanner", _fake_scanner) return tmp_path def test_checkpoint_names_drop_deleted_files(tmp_path, monkeypatch): from py.services.service_registry import ServiceRegistry existing = tmp_path / "keep.safetensors" existing.write_bytes(b"x") deleted = tmp_path / "deleted.safetensors" # referenced but never created raw_data = [ {"sub_type": "checkpoint", "file_path": str(existing)}, {"sub_type": "checkpoint", "file_path": str(deleted)}, # Wrong type must stay excluded by the sub_type filter. {"sub_type": "diffusion_model", "file_path": str(existing)}, ] async def _fake_scanner(): return _FakeScanner(raw_data, [str(tmp_path)]) monkeypatch.setattr(ServiceRegistry, "get_checkpoint_scanner", _fake_scanner) assert RandomCheckpointLoaderLM._get_checkpoint_names() == ["keep.safetensors"] def test_unet_names_drop_deleted_files(tmp_path, monkeypatch): from py.services.service_registry import ServiceRegistry existing = tmp_path / "keep.safetensors" existing.write_bytes(b"x") deleted = tmp_path / "deleted.safetensors" raw_data = [ {"sub_type": "diffusion_model", "file_path": str(existing)}, {"sub_type": "diffusion_model", "file_path": str(deleted)}, {"sub_type": "checkpoint", "file_path": str(existing)}, ] async def _fake_scanner(): return _FakeScanner(raw_data, [str(tmp_path)]) monkeypatch.setattr(ServiceRegistry, "get_checkpoint_scanner", _fake_scanner) assert RandomUNETLoaderLM._get_unet_names() == ["keep.safetensors"] def test_checkpoint_names_empty_when_scanner_fails(tmp_path, monkeypatch): from py.services.service_registry import ServiceRegistry def _boom(): raise RuntimeError("scanner not available") monkeypatch.setattr(ServiceRegistry, "get_checkpoint_scanner", _boom) assert RandomCheckpointLoaderLM._get_checkpoint_names() == [] def test_checkpoint_available_base_models(base_model_library): # "SDXL 1.0" is excluded because its file no longer exists on disk. assert RandomCheckpointLoaderLM._get_available_base_models() == [ "Any", "Flux.1 D", "Illustrious", ] def test_checkpoint_names_filtered_by_base_model(base_model_library): assert RandomCheckpointLoaderLM._get_checkpoint_names("Illustrious") == [ "illustrious.safetensors" ] assert RandomCheckpointLoaderLM._get_checkpoint_names("Any") == [ "flux.safetensors", "illustrious.safetensors", ] def test_unet_available_base_models(base_model_library): assert RandomUNETLoaderLM._get_available_base_models() == ["Any", "Flux.1 D"] def test_load_checkpoint_random_selection_uses_pool(base_model_library, monkeypatch): from py.nodes import random_checkpoint_loader as random_checkpoint_loader_module monkeypatch.setattr( random_checkpoint_loader_module, "get_checkpoint_info_absolute", lambda name: (str(base_model_library / name), {"file_path": name}), ) monkeypatch.setattr( random_checkpoint_loader_module.comfy.sd, "load_checkpoint_guess_config", lambda *a, **k: ("MODEL", "CLIP", "VAE", None), raising=False, ) node = RandomCheckpointLoaderLM() result = node.load_checkpoint( "ignored.safetensors", select_at_random=True, base_model="Illustrious" ) # Only one checkpoint matches "Illustrious", so the random pick is deterministic here. assert result[3] == "illustrious.safetensors" def test_load_checkpoint_random_selection_raises_when_pool_empty(base_model_library): node = RandomCheckpointLoaderLM() with pytest.raises(FileNotFoundError, match="No checkpoints found"): node.load_checkpoint( "ignored.safetensors", select_at_random=True, base_model="SDXL 1.0" ) def test_checkpoint_is_changed_forces_rerun_when_random(): assert RandomCheckpointLoaderLM.IS_CHANGED( "a.safetensors", select_at_random=True, base_model="Any" ) != RandomCheckpointLoaderLM.IS_CHANGED( "a.safetensors", select_at_random=True, base_model="Any" ) assert RandomCheckpointLoaderLM.IS_CHANGED( "a.safetensors", select_at_random=False, base_model="Any" ) == RandomCheckpointLoaderLM.IS_CHANGED( "a.safetensors", select_at_random=False, base_model="Any" )