9e8f1bbeed
Dashboard / frontend (push) Failing after 0s
Dashboard / api (push) Failing after 0s
Lint PowerShell / powershell-lint (ubuntu-latest) (push) Failing after 1s
Python Lint / Lint Python with Ruff (push) Failing after 1s
ShellCheck / Lint shell scripts (push) Failing after 1s
Matrix Smoke / linux-smoke (push) Failing after 1s
Matrix Smoke / distro: cachyos (push) Failing after 15s
Matrix Smoke / distro: linux-mint-21.3 (push) Failing after 15s
Matrix Smoke / distro: debian-12 (push) Failing after 5m21s
Matrix Smoke / distro: fedora-41 (push) Failing after 4m56s
Matrix Smoke / distro: ubuntu-24.04 (push) Failing after 2m13s
Matrix Smoke / distro: rocky-9 (push) Failing after 10m39s
Matrix Smoke / distro: manjaro (push) Failing after 12m11s
Matrix Smoke / distro: opensuse-tw (push) Failing after 11m53s
Matrix Smoke / distro: archlinux (push) Failing after 20m3s
Matrix Smoke / distro: ubuntu-22.04 (push) Failing after 13m49s
Validate .env Schema / tier-1-env-validation (push) Successful in 52s
Validate .env Schema / tier-2-env-validation (push) Successful in 44s
Validate .env Schema / tier-3-env-validation (push) Successful in 52s
Validate .env Schema / tier-4-env-validation (push) Successful in 51s
Validate Extensions Catalog / Check catalog is up-to-date (push) Failing after 9m47s
Secret Scan / Scan for secrets (push) Failing after 21m4s
Validate Docker Compose / Validate Docker Compose files (push) Has been cancelled
Python Type Check / Type check with mypy (push) Has been cancelled
Validate .env Schema / tier-0-env-validation (push) Has been cancelled
Test Linux / integration-smoke (push) Has been cancelled
Lint PowerShell / powershell-lint (windows-latest) (push) Has been cancelled
Matrix Smoke / macos-smoke (push) Has been cancelled
307 lines
13 KiB
Python
307 lines
13 KiB
Python
"""Tests for the AMD runtime diagnostic endpoint."""
|
|
|
|
from routers import gpu as gpu_router
|
|
|
|
|
|
def _patch_probe(monkeypatch, health="reachable", version="unknown", warning=None):
|
|
monkeypatch.setattr(
|
|
gpu_router,
|
|
"_probe_amd_health",
|
|
lambda _url: (health, version, warning),
|
|
)
|
|
|
|
|
|
def _patch_external_probe(
|
|
monkeypatch,
|
|
health="reachable",
|
|
version="unknown",
|
|
warnings=None,
|
|
loaded_model="Qwen3-0.6B-GGUF",
|
|
model_count=1,
|
|
):
|
|
async def _fake_probe(_api_base, _api_path):
|
|
return health, version, list(warnings or []), loaded_model, model_count
|
|
|
|
monkeypatch.setattr(gpu_router, "_probe_external_lemonade", _fake_probe)
|
|
|
|
|
|
def test_amd_runtime_not_amd(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "nvidia")
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == {
|
|
"available": False,
|
|
"reason": "not_amd",
|
|
"runtime": "none",
|
|
"location": "none",
|
|
"runtimeMode": "none",
|
|
"managedByODS": False,
|
|
"selectedBackend": "none",
|
|
"supportedBackends": [],
|
|
"defaultBackend": "none",
|
|
"version": "unknown",
|
|
"capabilities": [],
|
|
"warnings": [],
|
|
}
|
|
|
|
|
|
def test_amd_runtime_linux_container_lemonade(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "container")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "linux-container")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LEMONADE_CONTAINER_BASE_URL", "http://host.docker.internal:13305")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["available"] is True
|
|
assert payload["runtime"] == "lemonade"
|
|
assert payload["location"] == "container"
|
|
assert payload["runtimeMode"] == "linux-container"
|
|
assert payload["managedByODS"] is True
|
|
assert payload["selectedBackend"] == "rocm"
|
|
assert payload["supportedBackends"] == ["rocm"]
|
|
assert payload["defaultBackend"] == "rocm"
|
|
assert payload["apiBase"] == "http://llama-server:8080/api/v1"
|
|
assert payload["healthUrl"] == "http://llama-server:8080/api/v1/health"
|
|
assert payload["health"] == "reachable"
|
|
assert payload["capabilities"] == ["rocm"]
|
|
assert payload["warnings"] == []
|
|
|
|
|
|
def test_amd_runtime_windows_host_lemonade(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "host")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "windows-legacy-lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch, version="10.0.0")
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["runtime"] == "lemonade"
|
|
assert payload["location"] == "host"
|
|
assert payload["runtimeMode"] == "windows-legacy-lemonade"
|
|
assert payload["managedByODS"] is True
|
|
assert payload["selectedBackend"] == "vulkan"
|
|
assert payload["supportedBackends"] == ["vulkan"]
|
|
assert payload["apiBase"] == "http://host.docker.internal:8080/api/v1"
|
|
assert payload["healthUrl"] == "http://host.docker.internal:8080/api/v1/health"
|
|
assert payload["version"] == "10.0.0"
|
|
assert payload["capabilities"] == ["vulkan"]
|
|
|
|
|
|
def test_amd_runtime_external_lemonade_uses_container_base_url(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "auto")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "host")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "13305")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "auto")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "external-lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "false")
|
|
monkeypatch.setenv("LEMONADE_CONTAINER_BASE_URL", "http://host.docker.internal:13305/api/v1")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_external_probe(monkeypatch, version="10.2.0", loaded_model="Qwen3-0.6B-GGUF", model_count=2)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["runtime"] == "lemonade"
|
|
assert payload["location"] == "host"
|
|
assert payload["runtimeMode"] == "external-lemonade"
|
|
assert payload["managedByODS"] is False
|
|
assert payload["selectedBackend"] == "auto"
|
|
assert payload["supportedBackends"] == ["auto"]
|
|
assert payload["apiBase"] == "http://host.docker.internal:13305/api/v1"
|
|
assert payload["healthUrl"] == "http://host.docker.internal:13305/api/v1/health"
|
|
assert payload["version"] == "10.2.0"
|
|
assert payload["loadedModel"] == "Qwen3-0.6B-GGUF"
|
|
assert payload["modelCount"] == 2
|
|
assert payload["capabilities"] == ["auto"]
|
|
|
|
|
|
def test_amd_runtime_external_lemonade_surfaces_adapter_warnings(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "auto")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "host")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "13305")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "auto")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "external-lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "false")
|
|
monkeypatch.setenv("LEMONADE_CONTAINER_BASE_URL", "http://host.docker.internal:13305/api/v1")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_external_probe(
|
|
monkeypatch,
|
|
health="unhealthy",
|
|
version="unknown",
|
|
warnings=["health_auth_rejected"],
|
|
loaded_model=None,
|
|
model_count=None,
|
|
)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["health"] == "unhealthy"
|
|
assert payload["warnings"] == ["health_auth_rejected"]
|
|
assert "loadedModel" not in payload
|
|
assert "modelCount" not in payload
|
|
|
|
|
|
def test_amd_runtime_windows_host_llama_server_fallback(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "llama-server")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "host")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "windows-llama-server-fallback")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["runtime"] == "llama-server"
|
|
assert payload["location"] == "host"
|
|
assert payload["runtimeMode"] == "windows-llama-server-fallback"
|
|
assert payload["managedByODS"] is True
|
|
assert payload["selectedBackend"] == "vulkan"
|
|
assert payload["supportedBackends"] == ["vulkan"]
|
|
assert payload["apiBase"] == "http://host.docker.internal:8080/v1"
|
|
assert payload["healthUrl"] == "http://host.docker.internal:8080/health"
|
|
assert payload["health"] == "reachable"
|
|
assert payload["capabilities"] == ["vulkan"]
|
|
|
|
|
|
def test_amd_runtime_health_unreachable(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "container")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "linux-container")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch, health="unreachable", warning="health_unreachable")
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["available"] is True
|
|
assert payload["health"] == "unreachable"
|
|
assert payload["warnings"] == ["health_unreachable"]
|
|
|
|
|
|
def test_amd_runtime_uses_explicit_port(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "container")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "18080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "linux-container")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["apiBase"] == "http://llama-server:18080/api/v1"
|
|
assert payload["healthUrl"] == "http://llama-server:18080/api/v1/health"
|
|
assert payload["warnings"] == []
|
|
|
|
|
|
def test_amd_runtime_invalid_port_warns_and_falls_back(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "container")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "not-a-port")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "linux-container")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["apiBase"] == "http://llama-server:8080/api/v1"
|
|
assert "amd_port_invalid" in payload["warnings"]
|
|
|
|
|
|
def test_amd_runtime_warns_when_capabilities_missing(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "host")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.delenv("AMD_INFERENCE_SUPPORTED_BACKENDS", raising=False)
|
|
monkeypatch.delenv("AMD_INFERENCE_RUNTIME_MODE", raising=False)
|
|
monkeypatch.delenv("AMD_INFERENCE_MANAGED", raising=False)
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["available"] is True
|
|
assert payload["runtimeMode"] == "unknown"
|
|
assert payload["managedByODS"] is False
|
|
assert payload["selectedBackend"] == "vulkan"
|
|
assert payload["supportedBackends"] == []
|
|
assert payload["capabilities"] == []
|
|
assert "amd_supported_backends_env_missing" in payload["warnings"]
|
|
assert "amd_runtime_mode_env_missing" in payload["warnings"]
|
|
assert "amd_managed_env_missing" in payload["warnings"]
|
|
|
|
|
|
def test_amd_runtime_warns_when_selected_backend_not_supported(monkeypatch, test_client):
|
|
monkeypatch.setenv("GPU_BACKEND", "amd")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME", "lemonade")
|
|
monkeypatch.setenv("AMD_INFERENCE_BACKEND", "vulkan")
|
|
monkeypatch.setenv("AMD_INFERENCE_LOCATION", "container")
|
|
monkeypatch.setenv("AMD_INFERENCE_PORT", "8080")
|
|
monkeypatch.setenv("AMD_INFERENCE_SUPPORTED_BACKENDS", "rocm")
|
|
monkeypatch.setenv("AMD_INFERENCE_RUNTIME_MODE", "linux-container")
|
|
monkeypatch.setenv("AMD_INFERENCE_MANAGED", "true")
|
|
monkeypatch.setenv("LLM_API_BASE_PATH", "/api/v1")
|
|
_patch_probe(monkeypatch)
|
|
|
|
response = test_client.get("/api/gpu/amd-runtime", headers=test_client.auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
payload = response.json()
|
|
assert payload["selectedBackend"] == "vulkan"
|
|
assert payload["supportedBackends"] == ["rocm"]
|
|
assert "amd_selected_backend_not_supported" in payload["warnings"]
|