Files
bee/audit/internal/platform/pcie_link_check_test.go
T
Mikhail ChusavitinandClaude Sonnet 5 9e466b8a70 fix(pcie): stop misreporting empty/vanished slots as speed degradation
pcie-link's retrain check compared post-retrain speed against a port's
max capability without checking whether anything was actually seated
downstream. A switch downstream port with no card plugged in retrains
to zero lanes but still reports a reset-state speed, so it was
misreported as "retrained to Gen1, capable of Gen5" — indistinguishable
from a real degraded link.

Now a port that was already empty before the retrain is skipped (same
treatment as a disabled device: legitimately unpopulated slots are
common and shouldn't fail the check), while a device that answered
before the retrain and disappeared right after it still fails, with an
honest "no device detected downstream" message instead of a fabricated
speed reading.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 12:44:57 +03:00

115 lines
4.8 KiB
Go

package platform
import (
"strings"
"testing"
)
func TestClassifyGPUFromVendorClass(t *testing.T) {
cases := []struct {
name string
vendor string
class string
wantIsGPU bool
wantVendor string
}{
{"nvidia GPU", "0x10de", "0x030200", true, "nvidia"},
{"amd GPU", "0x1002", "0x030000", true, "amd"},
{"nvidia NIC (same vendor, not display class)", "0x10de", "0x020000", false, ""},
{"intel NIC", "0x8086", "0x020000", false, ""},
{"unrelated display-class vendor", "0x1234", "0x030000", false, ""},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
gotIsGPU, gotVendor := classifyGPUFromVendorClass(tc.vendor, tc.class)
if gotIsGPU != tc.wantIsGPU || gotVendor != tc.wantVendor {
t.Fatalf("classifyGPUFromVendorClass(%q,%q) = (%v,%q), want (%v,%q)",
tc.vendor, tc.class, gotIsGPU, gotVendor, tc.wantIsGPU, tc.wantVendor)
}
})
}
}
func TestRenderPCIeLinkCheckSummaryDegradedGPU(t *testing.T) {
findings := []pcieLinkFinding{
{BDF: "0000:0d:00.0", Description: "NVIDIA GPU", IsGPU: true, GPUVendor: "nvidia",
BeforeSpeed: "Gen1", AfterSpeed: "Gen1", MaxSpeed: "Gen5", Degraded: true},
{BDF: "0000:37:00.0", Description: "NVIDIA GPU", IsGPU: true, GPUVendor: "nvidia",
BeforeSpeed: "Gen1", AfterSpeed: "Gen5", MaxSpeed: "Gen5", Degraded: false},
{BDF: "0000:01:00.0", Description: "Mellanox NIC", IsGPU: false,
BeforeSpeed: "Gen3", AfterSpeed: "Gen4", MaxSpeed: "Gen4", Degraded: false},
}
summary := renderPCIeLinkCheckSummary(findings)
if !strings.Contains(summary, "gpu_nvidia_status=FAILED") {
t.Fatalf("expected gpu_nvidia_status=FAILED (one degraded GPU should fail the vendor group), got:\n%s", summary)
}
if !strings.Contains(summary, "other_status=OK") {
t.Fatalf("expected other_status=OK, got:\n%s", summary)
}
if !strings.Contains(summary, "overall_status=FAILED") {
t.Fatalf("expected overall_status=FAILED, got:\n%s", summary)
}
}
func TestRenderPCIeLinkCheckSummaryAllClean(t *testing.T) {
findings := []pcieLinkFinding{
{BDF: "0000:0d:00.0", IsGPU: true, GPUVendor: "nvidia", BeforeSpeed: "Gen1", AfterSpeed: "Gen5", MaxSpeed: "Gen5"},
{BDF: "0000:2c:00.0", Skipped: "device disabled (no data traffic; link state has no operational impact)"},
}
summary := renderPCIeLinkCheckSummary(findings)
if !strings.Contains(summary, "overall_status=OK") {
t.Fatalf("expected overall_status=OK, got:\n%s", summary)
}
if strings.Contains(summary, "other_status=") {
t.Fatalf("disabled/skipped-only device should not produce an other_status line, got:\n%s", summary)
}
}
func TestRenderPCIeLinkCheckSummaryEmptySlotDoesNotFail(t *testing.T) {
// An unpopulated switch downstream port (no card ever seated) is a
// normal, common configuration — it must not fail the SAT the way a
// genuinely degraded link does.
findings := []pcieLinkFinding{
{BDF: "0000:0d:00.0", IsGPU: true, GPUVendor: "nvidia", BeforeSpeed: "Gen5", AfterSpeed: "Gen5", MaxSpeed: "Gen5"},
{BDF: "0000:2a:00.0", Description: "PEX890xx PCIe Gen 5 Switch",
NotPresent: true, Skipped: "no device present downstream (empty slot/riser — nothing to retrain)"},
}
summary := renderPCIeLinkCheckSummary(findings)
if !strings.Contains(summary, "overall_status=OK") {
t.Fatalf("expected overall_status=OK for an empty slot, got:\n%s", summary)
}
if strings.Contains(summary, "other_status=") {
t.Fatalf("empty-slot-only device should not produce an other_status line, got:\n%s", summary)
}
report := renderPCIeLinkCheckReport(findings)
if !strings.Contains(report, "skipped: no device present downstream") {
t.Fatalf("expected empty slot to be reported as skipped, not degraded, got:\n%s", report)
}
if strings.Contains(report, "retrained to") {
t.Fatalf("empty slot must not be reported with a fabricated retrain speed, got:\n%s", report)
}
}
func TestRenderPCIeLinkCheckSummaryDeviceFellOffBusStillFails(t *testing.T) {
// A device that had a live link before the retrain and is gone right
// after it is a real regression, distinct from a slot that was never
// populated — this must still fail the check.
findings := []pcieLinkFinding{
{BDF: "0000:ab:00.0", Description: "PEX890xx PCIe Gen 5 Switch",
BeforeSpeed: "Gen5", AfterSpeed: "Gen5", MaxSpeed: "Gen5", Width: 0, NotPresent: true, Degraded: true},
}
summary := renderPCIeLinkCheckSummary(findings)
if !strings.Contains(summary, "overall_status=FAILED") {
t.Fatalf("expected overall_status=FAILED when a device disappears after retrain, got:\n%s", summary)
}
if !strings.Contains(summary, "no device detected downstream") {
t.Fatalf("expected an honest 'no device detected' reason, not a fabricated speed, got:\n%s", summary)
}
report := renderPCIeLinkCheckReport(findings)
if !strings.Contains(report, "FELL OFF BUS") {
t.Fatalf("expected FELL OFF BUS verdict in report, got:\n%s", report)
}
}