Files
wildminder-ComfyUI-VibeVoice/tests/test_device_utils.py
T
WildAi dc64c17c00 fix: cpu-first loading + neg-branch rope fix
- DF-001..006: loader builds the model entirely on CPU (state dict, load_state_dict, dtype cast, 4-bit); patcher owns the single H2D transfer after ComfyUI load_models_gpu arbitration. Removes the disk->VRAM->RAM->VRAM round-trip; peak load VRAM ~2x -> ~1x model size.

- BUG-011: negative CFG forward passed full-length position_ids with single-token inputs_embeds; transformers 5.x RoPE broadcast expanded q/k (not v) -> KV cache key/value desync -> SDPA crash [12,3] vs [12,2]. Now current-only position_ids.

- Tests: +36 device-flow, +4 neg-position-ids (red/green verified), +scheduler/e2e/mm-surface suites. Full suite 461p/5 pre-existing f/4s.

- Version 2.0.2; untrack .workbuddy-ai, ignore tmp/
2026-08-15 16:46:56 +03:00

171 lines
6.9 KiB
Python

"""Tests for modules/device_utils.py - Device detection and management."""
import torch
import pytest
from unittest.mock import patch, MagicMock
from ComfyUI_VibeVoice.modules.device_utils import (
DEVICE_CPU,
DEVICE_CUDA,
DEVICE_MPS,
DEVICE_XPU,
DEVICE_NPU,
get_available_devices,
get_torch_device,
get_offload_device,
is_gpu_device,
get_device_display_name,
)
class TestGetAvailableDevices:
"""Test get_available_devices function."""
def test_returns_list(self):
devices = get_available_devices()
assert isinstance(devices, list)
def test_includes_cpu(self):
devices = get_available_devices()
assert DEVICE_CPU in devices
def test_includes_cuda_when_available(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.is_nvidia.return_value = True
mock_mm.return_value.is_amd.return_value = False
mock_mm.return_value.mps_mode.return_value = False
devices = get_available_devices()
assert DEVICE_CUDA in devices
def test_includes_mps_when_available(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.is_nvidia.return_value = False
mock_mm.return_value.is_amd.return_value = False
mock_mm.return_value.mps_mode.return_value = True
devices = get_available_devices()
assert DEVICE_MPS in devices
def test_cpu_only_when_no_gpu(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.is_nvidia.return_value = False
mock_mm.return_value.is_amd.return_value = False
mock_mm.return_value.mps_mode.return_value = False
devices = get_available_devices()
assert devices == [DEVICE_CPU]
def test_excludes_mps_when_unavailable(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.is_nvidia.return_value = False
mock_mm.return_value.is_amd.return_value = False
mock_mm.return_value.mps_mode.return_value = False
devices = get_available_devices()
assert DEVICE_MPS not in devices
class TestGetTorchDevice:
"""Test get_torch_device function."""
def test_cpu_device(self):
device = get_torch_device(DEVICE_CPU)
assert device.type == DEVICE_CPU
def test_none_uses_default(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.get_torch_device.return_value = torch.device("cpu")
device = get_torch_device(None)
assert device is not None
def test_auto_uses_default(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device("auto")
assert device.type == "cuda"
def test_mps_available(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm, \
patch("torch.backends.mps.is_available", return_value=True):
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device(DEVICE_MPS)
assert device.type == DEVICE_MPS
def test_xpu_available(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm, \
patch("torch.xpu") as mock_xpu:
mock_xpu.is_available.return_value = True
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device(DEVICE_XPU)
assert device.type == DEVICE_XPU
def test_npu_available(self):
# NPU requires a special torch build that registers the "npu" device type.
# On standard builds torch.device("npu") raises, so skip there.
try:
torch.device(DEVICE_NPU)
except RuntimeError:
pytest.skip("torch build does not support the 'npu' device type")
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm, \
patch("torch.npu", create=True) as mock_npu:
mock_npu.is_available.return_value = True
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device(DEVICE_NPU)
assert device.type == DEVICE_NPU
def test_mps_unavailable_falls_back_and_warns(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm, \
patch("torch.backends.mps.is_available", return_value=False), \
patch("ComfyUI_VibeVoice.modules.device_utils.logger") as mock_logger:
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device(DEVICE_MPS)
assert device.type == "cuda"
mock_logger.warning.assert_called()
def test_unknown_device_falls_back_and_warns(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm, \
patch("ComfyUI_VibeVoice.modules.device_utils.logger") as mock_logger:
mock_mm.return_value.get_torch_device.return_value = torch.device("cuda")
device = get_torch_device("something_weird")
assert device.type == "cuda"
mock_logger.warning.assert_called()
class TestIsGpuDevice:
"""Test is_gpu_device function."""
def test_cuda_is_gpu(self):
assert is_gpu_device(DEVICE_CUDA) is True
def test_cpu_not_gpu(self):
assert is_gpu_device(DEVICE_CPU) is False
def test_mps_is_gpu(self):
assert is_gpu_device(DEVICE_MPS) is True
def test_case_insensitive(self):
assert is_gpu_device("CUDA") is True
assert is_gpu_device("CPU") is False
class TestGetOffloadDevice:
"""Test get_offload_device function."""
def test_returns_device(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management") as mock_mm:
mock_mm.return_value.intermediate_device.return_value = torch.device("cpu")
device = get_offload_device()
assert isinstance(device, torch.device)
class TestGetDeviceDisplayName:
"""Test get_device_display_name function."""
def test_cpu_name(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management"):
name = get_device_display_name(DEVICE_CPU)
assert "CPU" in name
def test_mps_name(self):
with patch("ComfyUI_VibeVoice.modules.device_utils._get_model_management"):
name = get_device_display_name(DEVICE_MPS)
assert "MPS" in name or "Apple" in name