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) } }) }