Add unit tests for host alert utility functions (alerts)

Test hostResourceID, hostDisplayName, hostInstanceName,
sanitizeHostComponent, sanitizeRAIDDevice, and hostDiskResourceID.
This commit is contained in:
rcourtman 2025-11-30 10:20:26 +00:00
parent 702e56c97a
commit 0d22d3d2e4

View file

@ -1,7 +1,10 @@
package alerts
import (
"strings"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
)
// TestSanitizeAlertKey tests the sanitizeAlertKey function
@ -587,3 +590,476 @@ func TestCalculateMedianInt_DoesNotModifyInput(t *testing.T) {
}
}
}
// TestHostResourceID tests the hostResourceID function
func TestHostResourceID(t *testing.T) {
tests := []struct {
name string
hostID string
want string
}{
{
name: "normal host ID",
hostID: "host-123",
want: "host:host-123",
},
{
name: "empty string returns unknown",
hostID: "",
want: "host:unknown",
},
{
name: "whitespace only returns unknown",
hostID: " ",
want: "host:unknown",
},
{
name: "whitespace is trimmed",
hostID: " host-456 ",
want: "host:host-456",
},
{
name: "UUID format",
hostID: "550e8400-e29b-41d4-a716-446655440000",
want: "host:550e8400-e29b-41d4-a716-446655440000",
},
{
name: "simple hostname",
hostID: "server1",
want: "host:server1",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := hostResourceID(tc.hostID)
if got != tc.want {
t.Errorf("hostResourceID(%q) = %q, want %q", tc.hostID, got, tc.want)
}
})
}
}
// TestHostDisplayName tests the hostDisplayName function
func TestHostDisplayName(t *testing.T) {
tests := []struct {
name string
host models.Host
want string
}{
{
name: "display name preferred",
host: models.Host{
ID: "id-123",
DisplayName: "My Server",
Hostname: "server.local",
},
want: "My Server",
},
{
name: "hostname when no display name",
host: models.Host{
ID: "id-123",
DisplayName: "",
Hostname: "server.local",
},
want: "server.local",
},
{
name: "ID when no display name or hostname",
host: models.Host{
ID: "id-123",
DisplayName: "",
Hostname: "",
},
want: "id-123",
},
{
name: "fallback to Host literal",
host: models.Host{
ID: "",
DisplayName: "",
Hostname: "",
},
want: "Host",
},
{
name: "whitespace display name ignored",
host: models.Host{
ID: "id-123",
DisplayName: " ",
Hostname: "server.local",
},
want: "server.local",
},
{
name: "whitespace hostname ignored",
host: models.Host{
ID: "id-123",
DisplayName: "",
Hostname: " ",
},
want: "id-123",
},
{
name: "display name with whitespace trimmed",
host: models.Host{
ID: "id-123",
DisplayName: " Server Name ",
Hostname: "server.local",
},
want: "Server Name",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := hostDisplayName(tc.host)
if got != tc.want {
t.Errorf("hostDisplayName() = %q, want %q", got, tc.want)
}
})
}
}
// TestHostInstanceName tests the hostInstanceName function
func TestHostInstanceName(t *testing.T) {
tests := []struct {
name string
host models.Host
want string
}{
{
name: "platform preferred",
host: models.Host{
Platform: "linux",
OSName: "Ubuntu 22.04",
},
want: "linux",
},
{
name: "os name when no platform",
host: models.Host{
Platform: "",
OSName: "Ubuntu 22.04",
},
want: "Ubuntu 22.04",
},
{
name: "fallback to Host Agent",
host: models.Host{
Platform: "",
OSName: "",
},
want: "Host Agent",
},
{
name: "whitespace platform ignored",
host: models.Host{
Platform: " ",
OSName: "Windows Server",
},
want: "Windows Server",
},
{
name: "whitespace os name ignored",
host: models.Host{
Platform: "",
OSName: " ",
},
want: "Host Agent",
},
{
name: "platform with whitespace trimmed",
host: models.Host{
Platform: " darwin ",
OSName: "macOS",
},
want: "darwin",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := hostInstanceName(tc.host)
if got != tc.want {
t.Errorf("hostInstanceName() = %q, want %q", got, tc.want)
}
})
}
}
// TestSanitizeHostComponent tests the sanitizeHostComponent function
func TestSanitizeHostComponent(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
// Empty/whitespace
{
name: "empty returns unknown",
input: "",
want: "unknown",
},
{
name: "whitespace only returns unknown",
input: " ",
want: "unknown",
},
// Basic strings
{
name: "lowercase passes through",
input: "myhost",
want: "myhost",
},
{
name: "uppercase converted to lowercase",
input: "MYHOST",
want: "myhost",
},
{
name: "mixed case normalized",
input: "MyHost",
want: "myhost",
},
{
name: "numbers preserved",
input: "host123",
want: "host123",
},
// Special characters become hyphens
{
name: "spaces become hyphen",
input: "my host",
want: "my-host",
},
{
name: "multiple spaces become single hyphen",
input: "my host",
want: "my-host",
},
{
name: "underscores become hyphen",
input: "my_host",
want: "my-host",
},
{
name: "slashes become hyphen",
input: "mnt/data",
want: "mnt-data",
},
{
name: "dots become hyphen",
input: "host.local",
want: "host-local",
},
{
name: "mixed special chars",
input: "host.local/data_01",
want: "host-local-data-01",
},
// Trimming leading/trailing hyphens
{
name: "leading special chars trimmed",
input: "--host",
want: "host",
},
{
name: "trailing special chars trimmed",
input: "host--",
want: "host",
},
{
name: "both ends trimmed",
input: "/host/",
want: "host",
},
// Only special chars
{
name: "only special chars returns unknown",
input: "@#$%",
want: "unknown",
},
{
name: "only hyphens returns unknown",
input: "---",
want: "unknown",
},
// Real-world examples
{
name: "linux mount path",
input: "/mnt/storage",
want: "mnt-storage",
},
{
name: "device path",
input: "/dev/sda1",
want: "dev-sda1",
},
{
name: "nvme device",
input: "nvme0n1p1",
want: "nvme0n1p1",
},
{
name: "IP address",
input: "192.168.1.1",
want: "192-168-1-1",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := sanitizeHostComponent(tc.input)
if got != tc.want {
t.Errorf("sanitizeHostComponent(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
}
// TestSanitizeRAIDDevice tests the sanitizeRAIDDevice function
func TestSanitizeRAIDDevice(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{
name: "with dev prefix",
input: "/dev/md0",
want: "md0",
},
{
name: "without dev prefix",
input: "md0",
want: "md0",
},
{
name: "nvme device",
input: "/dev/nvme0n1",
want: "nvme0n1",
},
{
name: "sda device",
input: "/dev/sda",
want: "sda",
},
{
name: "empty returns unknown",
input: "",
want: "unknown",
},
{
name: "only dev prefix",
input: "/dev/",
want: "unknown",
},
{
name: "md device with partition",
input: "/dev/md127p1",
want: "md127p1",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := sanitizeRAIDDevice(tc.input)
if got != tc.want {
t.Errorf("sanitizeRAIDDevice(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
}
// TestHostDiskResourceID tests the hostDiskResourceID function
func TestHostDiskResourceID(t *testing.T) {
tests := []struct {
name string
host models.Host
disk models.Disk
wantID string
wantNamePart string // Part of the name to check
}{
{
name: "mountpoint preferred",
host: models.Host{ID: "host-123"},
disk: models.Disk{
Mountpoint: "/mnt/data",
Device: "/dev/sda1",
},
wantID: "host:host-123/disk:mnt-data",
wantNamePart: "/mnt/data",
},
{
name: "device when no mountpoint",
host: models.Host{ID: "host-123"},
disk: models.Disk{
Mountpoint: "",
Device: "/dev/sda1",
},
wantID: "host:host-123/disk:dev-sda1",
wantNamePart: "/dev/sda1",
},
{
name: "fallback to disk literal",
host: models.Host{ID: "host-123"},
disk: models.Disk{
Mountpoint: "",
Device: "",
},
wantID: "host:host-123/disk:disk",
wantNamePart: "disk",
},
{
name: "root mount sanitizes to unknown",
host: models.Host{ID: "host-123"},
disk: models.Disk{
Mountpoint: "/",
Device: "/dev/sda1",
},
wantID: "host:host-123/disk:unknown",
wantNamePart: "/",
},
{
name: "whitespace mountpoint uses device",
host: models.Host{ID: "host-123"},
disk: models.Disk{
Mountpoint: " ",
Device: "/dev/sda1",
},
wantID: "host:host-123/disk:dev-sda1",
wantNamePart: "/dev/sda1",
},
{
name: "includes host display name",
host: models.Host{
ID: "host-123",
DisplayName: "My Server",
},
disk: models.Disk{
Mountpoint: "/data",
},
wantID: "host:host-123/disk:data",
wantNamePart: "My Server",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
gotID, gotName := hostDiskResourceID(tc.host, tc.disk)
if gotID != tc.wantID {
t.Errorf("hostDiskResourceID() ID = %q, want %q", gotID, tc.wantID)
}
if !strings.Contains(gotName, tc.wantNamePart) {
t.Errorf("hostDiskResourceID() Name = %q, want to contain %q", gotName, tc.wantNamePart)
}
})
}
}