e3c8979e8d
- cmd/fn/doctor.go - cmd/fn/main.go - cpp/apps/primitives_gallery/playground/tables/CMakeLists.txt - cpp/apps/primitives_gallery/playground/tables/data_table.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.cpp - cpp/apps/primitives_gallery/playground/tables/data_table_logic.h - cpp/apps/primitives_gallery/playground/tables/self_test.cpp - cpp/apps/primitives_gallery/playground/tables/tql.cpp - cpp/apps/primitives_gallery/playground/tables/viz.cpp - cpp/apps/primitives_gallery/playground/tables/viz.h - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
166 lines
4.6 KiB
Go
166 lines
4.6 KiB
Go
package infra
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestGetGpuInfoNoGpu verifica que la funcion retorna slice vacio sin error
|
|
// cuando nvidia-smi no esta instalado o no hay GPU NVIDIA presente.
|
|
// Este test pasa en cualquier maquina, con o sin GPU.
|
|
func TestGetGpuInfoNoGpu(t *testing.T) {
|
|
t.Run("retorna slice vacio y nil cuando no hay GPU NVIDIA", func(t *testing.T) {
|
|
gpus, err := GetGpuInfo()
|
|
if err != nil {
|
|
t.Errorf("GetGpuInfo() error inesperado: %v", err)
|
|
}
|
|
// En maquinas sin nvidia-smi el resultado debe ser un slice vacio (no nil)
|
|
if gpus == nil {
|
|
t.Error("GetGpuInfo() retorno nil, se esperaba slice vacio []GpuInfo{}")
|
|
}
|
|
})
|
|
}
|
|
|
|
// parseCsvNvidiaSmi replica la logica de parsing de GetGpuInfo para tests unitarios.
|
|
// Recibe el output de nvidia-smi --format=csv,noheader,nounits y retorna []GpuInfo.
|
|
func parseCsvNvidiaSmi(output string) ([]GpuInfo, error) {
|
|
trimmed := strings.TrimSpace(output)
|
|
if trimmed == "" {
|
|
return []GpuInfo{}, nil
|
|
}
|
|
lines := strings.Split(trimmed, "\n")
|
|
gpus := make([]GpuInfo, 0, len(lines))
|
|
for _, line := range lines {
|
|
parts := strings.Split(line, ",")
|
|
if len(parts) < 6 {
|
|
continue
|
|
}
|
|
idx, _ := strconv.Atoi(strings.TrimSpace(parts[0]))
|
|
totalMb, _ := strconv.Atoi(strings.TrimSpace(parts[2]))
|
|
freeMb, _ := strconv.Atoi(strings.TrimSpace(parts[3]))
|
|
gpus = append(gpus, GpuInfo{
|
|
Index: idx,
|
|
Name: strings.TrimSpace(parts[1]),
|
|
VramTotalMb: totalMb,
|
|
VramFreeMb: freeMb,
|
|
DriverVersion: strings.TrimSpace(parts[4]),
|
|
CudaVersion: strings.TrimSpace(parts[5]),
|
|
})
|
|
}
|
|
return gpus, nil
|
|
}
|
|
|
|
// TestParseCsvNvidiaSmi verifica el parsing de la salida CSV de nvidia-smi
|
|
// sin requerir GPU real ni nvidia-smi instalado.
|
|
func TestParseCsvNvidiaSmi(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
csvInput string
|
|
wantLen int
|
|
wantIndex int
|
|
wantName string
|
|
wantVramTotal int
|
|
wantVramFree int
|
|
wantDriver string
|
|
wantCuda string
|
|
}{
|
|
{
|
|
name: "linea GPU RTX 3080 tipica",
|
|
csvInput: "0, NVIDIA GeForce RTX 3080, 10240, 8192, 550.54.15, 12.4",
|
|
wantLen: 1,
|
|
wantIndex: 0,
|
|
wantName: "NVIDIA GeForce RTX 3080",
|
|
wantVramTotal: 10240,
|
|
wantVramFree: 8192,
|
|
wantDriver: "550.54.15",
|
|
wantCuda: "12.4",
|
|
},
|
|
{
|
|
name: "dos GPUs en el CSV",
|
|
csvInput: "0, GPU A, 8192, 4096, 525.0, 12.0\n1, GPU B, 24576, 20000, 525.0, 12.0",
|
|
wantLen: 2,
|
|
},
|
|
{
|
|
name: "CSV vacio retorna slice vacio",
|
|
csvInput: "",
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "linea con menos de 6 campos se ignora",
|
|
csvInput: "0, GPU, 8192",
|
|
wantLen: 0,
|
|
},
|
|
{
|
|
name: "espacios extra en los valores se eliminan",
|
|
csvInput: " 1 , NVIDIA RTX 4090 , 24576 , 20000 , 545.0 , 12.6 ",
|
|
wantLen: 1,
|
|
wantIndex: 1,
|
|
wantName: "NVIDIA RTX 4090",
|
|
wantVramTotal: 24576,
|
|
wantVramFree: 20000,
|
|
wantDriver: "545.0",
|
|
wantCuda: "12.6",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
gpus, err := parseCsvNvidiaSmi(tc.csvInput)
|
|
if err != nil {
|
|
t.Fatalf("error inesperado: %v", err)
|
|
}
|
|
if len(gpus) != tc.wantLen {
|
|
t.Fatalf("len(gpus) = %d, quería %d", len(gpus), tc.wantLen)
|
|
}
|
|
if tc.wantLen == 1 {
|
|
g := gpus[0]
|
|
if g.Index != tc.wantIndex {
|
|
t.Errorf("Index = %d, quería %d", g.Index, tc.wantIndex)
|
|
}
|
|
if g.Name != tc.wantName {
|
|
t.Errorf("Name = %q, quería %q", g.Name, tc.wantName)
|
|
}
|
|
if g.VramTotalMb != tc.wantVramTotal {
|
|
t.Errorf("VramTotalMb = %d, quería %d", g.VramTotalMb, tc.wantVramTotal)
|
|
}
|
|
if g.VramFreeMb != tc.wantVramFree {
|
|
t.Errorf("VramFreeMb = %d, quería %d", g.VramFreeMb, tc.wantVramFree)
|
|
}
|
|
if g.DriverVersion != tc.wantDriver {
|
|
t.Errorf("DriverVersion = %q, quería %q", g.DriverVersion, tc.wantDriver)
|
|
}
|
|
if g.CudaVersion != tc.wantCuda {
|
|
t.Errorf("CudaVersion = %q, quería %q", g.CudaVersion, tc.wantCuda)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGpuInfoStruct verifica los campos del tipo GpuInfo.
|
|
func TestGpuInfoStruct(t *testing.T) {
|
|
t.Run("campos del struct GpuInfo correctos", func(t *testing.T) {
|
|
g := GpuInfo{
|
|
Index: 0,
|
|
Name: "NVIDIA GeForce GTX 1080",
|
|
VramTotalMb: 8192,
|
|
VramFreeMb: 6144,
|
|
DriverVersion: "470.0",
|
|
CudaVersion: "11.4",
|
|
}
|
|
if g.Index != 0 {
|
|
t.Errorf("Index = %d", g.Index)
|
|
}
|
|
if g.Name != "NVIDIA GeForce GTX 1080" {
|
|
t.Errorf("Name = %q", g.Name)
|
|
}
|
|
if g.VramTotalMb != 8192 {
|
|
t.Errorf("VramTotalMb = %d", g.VramTotalMb)
|
|
}
|
|
if g.VramFreeMb != 6144 {
|
|
t.Errorf("VramFreeMb = %d", g.VramFreeMb)
|
|
}
|
|
})
|
|
}
|