mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 14:07:55 +00:00
`_total_ram_gb()` had branches for Darwin (sysctl) and Linux (/proc/meminfo) but no Windows path, so `jarvis init` reported "0.0 GB RAM" on every Windows host. The downstream `recommend_model()` then fell back to VRAM-only sizing, often selecting a smaller tier than the system can actually run. Add a Windows branch that calls `GlobalMemoryStatusEx` via ctypes — no new dependency. Add a platform-skip-aware test for each OS branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
161 lines
5.6 KiB
Python
161 lines
5.6 KiB
Python
"""Tests for hardware detection, GPU vendor identification,
|
|
and engine recommendation."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from openjarvis.core.config import (
|
|
GpuInfo,
|
|
_detect_amd_gpu,
|
|
_detect_apple_gpu,
|
|
_detect_nvidia_gpu,
|
|
_total_ram_gb,
|
|
recommend_engine,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Hardware detection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestDetectHardware:
|
|
"""Tests for the top-level detect_hardware() function."""
|
|
|
|
@patch("openjarvis.core.config.shutil.which", return_value="/usr/bin/nvidia-smi")
|
|
@patch(
|
|
"openjarvis.core.config._run_cmd",
|
|
return_value="NVIDIA A100-SXM4-80GB, 81920, 1",
|
|
)
|
|
def test_detect_nvidia_gpu(self, mock_run, mock_which):
|
|
gpu = _detect_nvidia_gpu()
|
|
assert gpu is not None
|
|
assert gpu.vendor == "nvidia"
|
|
assert "A100" in gpu.name
|
|
assert gpu.vram_gb == 80.0
|
|
assert gpu.count == 1
|
|
|
|
@patch("openjarvis.core.config.shutil.which", return_value="/usr/bin/rocm-smi")
|
|
@patch(
|
|
"openjarvis.core.config._run_cmd",
|
|
side_effect=[
|
|
"AMD Instinct MI300X", # --showproductname
|
|
"GPU[0] : vram Total Memory (B): 206158430208", # --showmeminfo vram
|
|
"GPU[0] : Some info", # --showallinfo
|
|
],
|
|
)
|
|
def test_detect_amd_gpu(self, mock_run, mock_which):
|
|
gpu = _detect_amd_gpu()
|
|
assert gpu is not None
|
|
assert gpu.vendor == "amd"
|
|
assert "MI300X" in gpu.name
|
|
|
|
@patch("openjarvis.core.config.platform.system", return_value="Darwin")
|
|
@patch(
|
|
"openjarvis.core.config._run_cmd",
|
|
return_value=(
|
|
"Graphics/Displays:\n"
|
|
" Apple M4 Max:\n"
|
|
" Chipset Model: Apple M4 Max\n"
|
|
" Type: GPU\n"
|
|
" Bus: Built-In\n"
|
|
),
|
|
)
|
|
def test_detect_apple_silicon(self, mock_run, mock_system):
|
|
gpu = _detect_apple_gpu()
|
|
assert gpu is not None
|
|
assert gpu.vendor == "apple"
|
|
assert "M4 Max" in gpu.name
|
|
|
|
@patch("openjarvis.core.config.shutil.which", return_value=None)
|
|
@patch("openjarvis.core.config.platform.system", return_value="Linux")
|
|
def test_detect_no_gpu(self, mock_system, mock_which):
|
|
"""All GPU detection methods return None when no GPU is present."""
|
|
assert _detect_nvidia_gpu() is None
|
|
assert _detect_amd_gpu() is None
|
|
assert _detect_apple_gpu() is None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# RAM detection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestTotalRamGb:
|
|
"""Tests for _total_ram_gb() across platforms."""
|
|
|
|
@pytest.mark.skipif(sys.platform != "win32", reason="Requires Windows")
|
|
def test_total_ram_gb_windows(self):
|
|
"""On Windows, GlobalMemoryStatusEx must return a positive RAM value."""
|
|
ram = _total_ram_gb()
|
|
assert ram > 0, f"Expected > 0 GB on Windows, got {ram}"
|
|
|
|
@pytest.mark.skipif(sys.platform != "darwin", reason="Requires macOS")
|
|
def test_total_ram_gb_darwin(self):
|
|
ram = _total_ram_gb()
|
|
assert ram > 0, f"Expected > 0 GB on macOS, got {ram}"
|
|
|
|
@pytest.mark.skipif(not sys.platform.startswith("linux"), reason="Requires Linux")
|
|
def test_total_ram_gb_linux(self):
|
|
ram = _total_ram_gb()
|
|
assert ram > 0, f"Expected > 0 GB on Linux, got {ram}"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Engine recommendation
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestRecommendEngine:
|
|
"""Tests for recommend_engine() logic across hardware profiles."""
|
|
|
|
def test_nvidia_datacenter_vllm(self, hardware_nvidia):
|
|
assert recommend_engine(hardware_nvidia) == "vllm"
|
|
|
|
def test_nvidia_consumer_ollama(self, hardware_nvidia_consumer):
|
|
assert recommend_engine(hardware_nvidia_consumer) == "ollama"
|
|
|
|
def test_amd_vllm(self, hardware_amd):
|
|
assert recommend_engine(hardware_amd) == "vllm"
|
|
|
|
def test_apple_mlx(self, hardware_apple):
|
|
assert recommend_engine(hardware_apple) == "mlx"
|
|
|
|
def test_cpu_only_llamacpp(self, hardware_cpu_only):
|
|
assert recommend_engine(hardware_cpu_only) == "llamacpp"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Dataclass serialization / field access
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestHardwareProfileSerialization:
|
|
"""Tests that dataclass fields are accessible and hold correct values."""
|
|
|
|
def test_gpu_info_fields(self, nvidia_gpu):
|
|
assert nvidia_gpu.vendor == "nvidia"
|
|
assert nvidia_gpu.name == "NVIDIA A100-SXM4-80GB"
|
|
assert nvidia_gpu.vram_gb == 80.0
|
|
assert nvidia_gpu.count == 1
|
|
|
|
def test_hardware_info_fields(self, hardware_nvidia):
|
|
assert hardware_nvidia.platform == "linux"
|
|
assert hardware_nvidia.cpu_brand == "AMD EPYC 7763"
|
|
assert hardware_nvidia.cpu_count == 64
|
|
assert hardware_nvidia.ram_gb == 512.0
|
|
assert hardware_nvidia.gpu is not None
|
|
|
|
def test_vram_sufficient_for_model(self):
|
|
"""Verify that VRAM capacity can be checked against a model requirement."""
|
|
gpu = GpuInfo(vendor="nvidia", name="NVIDIA A100", vram_gb=80.0, count=1)
|
|
model_requirement_gb = 40.0
|
|
assert gpu.vram_gb >= model_requirement_gb
|
|
|
|
small_gpu = GpuInfo(vendor="nvidia", name="RTX 3060", vram_gb=12.0, count=1)
|
|
large_model_gb = 70.0
|
|
assert small_gpu.vram_gb < large_model_gb
|