Files

85 lines
3.1 KiB
Go

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: `<script>x</script>`, Nodes: []models.TopologyNode{{ID: "cpu:0", Kind: "cpu", Label: "CPU 0", Socket: intp(0)}}}))
if strings.Contains(body, `<script>x</script>`) {
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)
}
}
}