package topology import ( "encoding/json" "strings" "testing" "git.mchus.pro/mchus/logpile/internal/exporter" "git.mchus.pro/mchus/logpile/internal/models" ) func intp(v int) *int { return &v } func TestBuildDistinguishesNUMAZeroFromUnknown(t *testing.T) { snapshot := &exporter.ReanimatorExport{Hardware: exporter.ReanimatorHardware{ Board: exporter.ReanimatorBoard{SerialNumber: "SN1"}, CPUs: []exporter.ReanimatorCPU{{Socket: 0}, {Socket: 1}}, PCIeDevices: []exporter.ReanimatorPCIe{ {Slot: "0000:01:00.0", DeviceClass: "VideoController", Model: "GPU A", NUMANode: intp(0)}, {Slot: "0000:02:00.0", DeviceClass: "NetworkController", Model: "NIC A", NUMANode: nil}, }, }} doc := Build(snapshot, nil) var gpuAttached, nicAttached bool for _, e := range doc.Edges { gpuAttached = gpuAttached || (e.From == "cpu:0" && e.To == "gpu:0000:01:00.0") nicAttached = nicAttached || strings.Contains(e.To, "nic:") } if !gpuAttached { t.Fatal("NUMA node 0 GPU was not attached to CPU 0") } if nicAttached { t.Fatal("unknown-affinity NIC must not be attached") } body, err := json.Marshal(doc) if err != nil { t.Fatal(err) } if !strings.Contains(string(body), `"numa_node":0`) { t.Fatalf("topology JSON lost NUMA zero: %s", body) } } func TestBuildUsesBeeStaticEvidence(t *testing.T) { snapshot := &exporter.ReanimatorExport{Hardware: exporter.ReanimatorHardware{ Board: exporter.ReanimatorBoard{SerialNumber: "SN1"}, CPUs: []exporter.ReanimatorCPU{{Socket: 0}, {Socket: 1}}, Memory: []exporter.ReanimatorMemory{{Slot: "DIMM000(A)", SerialNumber: "M1", Status: "OK"}}, Storage: []exporter.ReanimatorStorage{{Slot: "0:0:0:0", SerialNumber: "D1", Model: "Disk"}}, PCIeDevices: []exporter.ReanimatorPCIe{ {Slot: "0000:01:00.0", DeviceClass: "StorageController", NUMANode: intp(0)}, {Slot: "0000:31:00.0", DeviceClass: "VideoController", Model: "GPU 0", NUMANode: intp(0)}, {Slot: "0000:32:00.0", DeviceClass: "VideoController", Model: "GPU 1", NUMANode: intp(0)}, }, }} e := &models.TopologyEvidence{ DIMMType17: "Memory Device\n Locator: DIMM000(A)\n Bank Locator: Node0_Channel0", StorageMap: "sda hctl=0:0:0:0 ctrl=0000:01:00.0", NVIDIAQueryCSV: "0, 0000:31:00.0\n1, 0000:32:00.0\n", NVIDIATopology: " GPU0 GPU1\nGPU0 X NV4\nGPU1 NV4 X\n", } doc := Build(snapshot, e) kinds := map[string]int{} for _, edge := range doc.Edges { kinds[edge.Kind]++ } for _, kind := range []string{"memory", "storage", "nvlink"} { if kinds[kind] == 0 { t.Fatalf("missing %s edge: %+v", kind, doc.Edges) } } } func TestRenderHTMLIsStaticAndEscapesLabels(t *testing.T) { body := string(RenderHTML(&models.TopologyDocument{Version: ContractVersion, Title: ``, Nodes: []models.TopologyNode{{ID: "cpu:0", Kind: "cpu", Label: "CPU 0", Socket: intp(0)}}})) if strings.Contains(body, ``) { t.Fatal("title was not escaped") } for _, forbidden := range []string{"setInterval(", "fetch(", "nvidia-smi"} { if strings.Contains(body, forbidden) { t.Fatalf("rendered page contains live behavior %q", forbidden) } } }