mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
392 lines
9.5 KiB
Go
392 lines
9.5 KiB
Go
package host
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestReport_JSONMarshal(t *testing.T) {
|
|
report := Report{
|
|
Agent: AgentInfo{
|
|
ID: "agent-1",
|
|
Version: "1.0.0",
|
|
Type: "unified",
|
|
IntervalSeconds: 30,
|
|
Hostname: "myhost",
|
|
},
|
|
Host: HostInfo{
|
|
ID: "host-1",
|
|
Hostname: "myhost",
|
|
DisplayName: "My Host",
|
|
Platform: "linux",
|
|
CPUCount: 4,
|
|
UptimeSeconds: 86400,
|
|
LoadAverage: []float64{0.5, 0.7, 0.9},
|
|
},
|
|
Metrics: Metrics{
|
|
CPUUsagePercent: 25.5,
|
|
Memory: MemoryMetric{
|
|
TotalBytes: 16000000000,
|
|
UsedBytes: 8000000000,
|
|
FreeBytes: 8000000000,
|
|
Usage: 50.0,
|
|
},
|
|
},
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
data, err := json.Marshal(report)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal Report: %v", err)
|
|
}
|
|
|
|
var decoded Report
|
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
|
t.Fatalf("Failed to unmarshal Report: %v", err)
|
|
}
|
|
|
|
if decoded.Agent.ID != report.Agent.ID {
|
|
t.Errorf("Agent.ID = %q, want %q", decoded.Agent.ID, report.Agent.ID)
|
|
}
|
|
if decoded.Host.Hostname != report.Host.Hostname {
|
|
t.Errorf("Host.Hostname = %q, want %q", decoded.Host.Hostname, report.Host.Hostname)
|
|
}
|
|
if decoded.Metrics.CPUUsagePercent != report.Metrics.CPUUsagePercent {
|
|
t.Errorf("Metrics.CPUUsagePercent = %f, want %f", decoded.Metrics.CPUUsagePercent, report.Metrics.CPUUsagePercent)
|
|
}
|
|
}
|
|
|
|
func TestAgentInfo_Fields(t *testing.T) {
|
|
agent := AgentInfo{
|
|
ID: "agent-123",
|
|
Version: "2.0.0",
|
|
Type: "host",
|
|
IntervalSeconds: 60,
|
|
Hostname: "server1",
|
|
}
|
|
|
|
if agent.ID != "agent-123" {
|
|
t.Errorf("ID = %q, want agent-123", agent.ID)
|
|
}
|
|
if agent.Version != "2.0.0" {
|
|
t.Errorf("Version = %q, want 2.0.0", agent.Version)
|
|
}
|
|
if agent.Type != "host" {
|
|
t.Errorf("Type = %q, want host", agent.Type)
|
|
}
|
|
if agent.IntervalSeconds != 60 {
|
|
t.Errorf("IntervalSeconds = %d, want 60", agent.IntervalSeconds)
|
|
}
|
|
if agent.Hostname != "server1" {
|
|
t.Errorf("Hostname = %q, want server1", agent.Hostname)
|
|
}
|
|
}
|
|
|
|
func TestHostInfo_Fields(t *testing.T) {
|
|
host := HostInfo{
|
|
ID: "host-456",
|
|
Hostname: "myserver",
|
|
DisplayName: "My Server",
|
|
MachineID: "abc123",
|
|
Platform: "linux",
|
|
OSName: "Ubuntu",
|
|
OSVersion: "22.04",
|
|
KernelVersion: "5.15.0",
|
|
Architecture: "x86_64",
|
|
CPUModel: "Intel Core i7",
|
|
CPUCount: 8,
|
|
UptimeSeconds: 172800,
|
|
LoadAverage: []float64{1.0, 0.8, 0.6},
|
|
}
|
|
|
|
if host.ID != "host-456" {
|
|
t.Errorf("ID = %q, want host-456", host.ID)
|
|
}
|
|
if host.Platform != "linux" {
|
|
t.Errorf("Platform = %q, want linux", host.Platform)
|
|
}
|
|
if host.CPUCount != 8 {
|
|
t.Errorf("CPUCount = %d, want 8", host.CPUCount)
|
|
}
|
|
if len(host.LoadAverage) != 3 {
|
|
t.Errorf("LoadAverage length = %d, want 3", len(host.LoadAverage))
|
|
}
|
|
}
|
|
|
|
func TestMemoryMetric_Fields(t *testing.T) {
|
|
mem := MemoryMetric{
|
|
TotalBytes: 32000000000,
|
|
UsedBytes: 16000000000,
|
|
FreeBytes: 16000000000,
|
|
Usage: 50.0,
|
|
SwapTotal: 8000000000,
|
|
SwapUsed: 2000000000,
|
|
}
|
|
|
|
if mem.TotalBytes != 32000000000 {
|
|
t.Errorf("TotalBytes = %d, want 32000000000", mem.TotalBytes)
|
|
}
|
|
if mem.Usage != 50.0 {
|
|
t.Errorf("Usage = %f, want 50.0", mem.Usage)
|
|
}
|
|
if mem.SwapTotal != 8000000000 {
|
|
t.Errorf("SwapTotal = %d, want 8000000000", mem.SwapTotal)
|
|
}
|
|
}
|
|
|
|
func TestDisk_Fields(t *testing.T) {
|
|
disk := Disk{
|
|
Device: "/dev/sda1",
|
|
Mountpoint: "/",
|
|
Filesystem: "ext4",
|
|
Type: "ext4",
|
|
TotalBytes: 500000000000,
|
|
UsedBytes: 250000000000,
|
|
FreeBytes: 250000000000,
|
|
Usage: 50.0,
|
|
}
|
|
|
|
if disk.Device != "/dev/sda1" {
|
|
t.Errorf("Device = %q, want /dev/sda1", disk.Device)
|
|
}
|
|
if disk.Mountpoint != "/" {
|
|
t.Errorf("Mountpoint = %q, want /", disk.Mountpoint)
|
|
}
|
|
if disk.Usage != 50.0 {
|
|
t.Errorf("Usage = %f, want 50.0", disk.Usage)
|
|
}
|
|
}
|
|
|
|
func TestNetworkInterface_Fields(t *testing.T) {
|
|
speed := int64(1000)
|
|
net := NetworkInterface{
|
|
Name: "eth0",
|
|
MAC: "00:11:22:33:44:55",
|
|
Addresses: []string{"192.168.1.100", "fe80::1"},
|
|
RXBytes: 1000000,
|
|
TXBytes: 500000,
|
|
SpeedMbps: &speed,
|
|
}
|
|
|
|
if net.Name != "eth0" {
|
|
t.Errorf("Name = %q, want eth0", net.Name)
|
|
}
|
|
if net.MAC != "00:11:22:33:44:55" {
|
|
t.Errorf("MAC = %q, want 00:11:22:33:44:55", net.MAC)
|
|
}
|
|
if len(net.Addresses) != 2 {
|
|
t.Errorf("Addresses length = %d, want 2", len(net.Addresses))
|
|
}
|
|
if *net.SpeedMbps != 1000 {
|
|
t.Errorf("SpeedMbps = %d, want 1000", *net.SpeedMbps)
|
|
}
|
|
}
|
|
|
|
func TestSensors_Fields(t *testing.T) {
|
|
sensors := Sensors{
|
|
TemperatureCelsius: map[string]float64{
|
|
"cpu_package": 45.0,
|
|
"cpu_core_0": 43.0,
|
|
"cpu_core_1": 44.0,
|
|
},
|
|
FanRPM: map[string]float64{
|
|
"cpu_fan": 1200.0,
|
|
},
|
|
Additional: map[string]float64{
|
|
"voltage": 12.0,
|
|
},
|
|
}
|
|
|
|
if len(sensors.TemperatureCelsius) != 3 {
|
|
t.Errorf("TemperatureCelsius count = %d, want 3", len(sensors.TemperatureCelsius))
|
|
}
|
|
if sensors.TemperatureCelsius["cpu_package"] != 45.0 {
|
|
t.Errorf("cpu_package temp = %f, want 45.0", sensors.TemperatureCelsius["cpu_package"])
|
|
}
|
|
if sensors.FanRPM["cpu_fan"] != 1200.0 {
|
|
t.Errorf("cpu_fan RPM = %f, want 1200.0", sensors.FanRPM["cpu_fan"])
|
|
}
|
|
}
|
|
|
|
func TestRAIDArray_Fields(t *testing.T) {
|
|
array := RAIDArray{
|
|
Device: "/dev/md0",
|
|
Name: "myarray",
|
|
Level: "raid1",
|
|
State: "clean",
|
|
TotalDevices: 2,
|
|
ActiveDevices: 2,
|
|
WorkingDevices: 2,
|
|
FailedDevices: 0,
|
|
SpareDevices: 0,
|
|
UUID: "12345678:90abcdef:12345678:90abcdef",
|
|
RebuildPercent: 0,
|
|
RebuildSpeed: "",
|
|
Devices: []RAIDDevice{
|
|
{Device: "/dev/sda1", State: "active sync", Slot: 0},
|
|
{Device: "/dev/sdb1", State: "active sync", Slot: 1},
|
|
},
|
|
}
|
|
|
|
if array.Device != "/dev/md0" {
|
|
t.Errorf("Device = %q, want /dev/md0", array.Device)
|
|
}
|
|
if array.Level != "raid1" {
|
|
t.Errorf("Level = %q, want raid1", array.Level)
|
|
}
|
|
if array.State != "clean" {
|
|
t.Errorf("State = %q, want clean", array.State)
|
|
}
|
|
if len(array.Devices) != 2 {
|
|
t.Errorf("Devices count = %d, want 2", len(array.Devices))
|
|
}
|
|
}
|
|
|
|
func TestRAIDDevice_Fields(t *testing.T) {
|
|
device := RAIDDevice{
|
|
Device: "/dev/sda1",
|
|
State: "active sync",
|
|
Slot: 0,
|
|
}
|
|
|
|
if device.Device != "/dev/sda1" {
|
|
t.Errorf("Device = %q, want /dev/sda1", device.Device)
|
|
}
|
|
if device.State != "active sync" {
|
|
t.Errorf("State = %q, want active sync", device.State)
|
|
}
|
|
if device.Slot != 0 {
|
|
t.Errorf("Slot = %d, want 0", device.Slot)
|
|
}
|
|
}
|
|
|
|
func TestRAIDArray_Degraded(t *testing.T) {
|
|
array := RAIDArray{
|
|
Device: "/dev/md1",
|
|
Level: "raid5",
|
|
State: "clean, degraded",
|
|
TotalDevices: 3,
|
|
ActiveDevices: 2,
|
|
WorkingDevices: 2,
|
|
FailedDevices: 1,
|
|
SpareDevices: 0,
|
|
Devices: []RAIDDevice{
|
|
{Device: "/dev/sda1", State: "active sync", Slot: 0},
|
|
{Device: "/dev/sdb1", State: "faulty", Slot: -1},
|
|
{Device: "/dev/sdc1", State: "active sync", Slot: 2},
|
|
},
|
|
}
|
|
|
|
if array.FailedDevices != 1 {
|
|
t.Errorf("FailedDevices = %d, want 1", array.FailedDevices)
|
|
}
|
|
if array.State != "clean, degraded" {
|
|
t.Errorf("State = %q, want 'clean, degraded'", array.State)
|
|
}
|
|
}
|
|
|
|
func TestRAIDArray_Rebuilding(t *testing.T) {
|
|
array := RAIDArray{
|
|
Device: "/dev/md2",
|
|
Level: "raid6",
|
|
State: "active, recovering",
|
|
RebuildPercent: 42.5,
|
|
RebuildSpeed: "50000K/sec",
|
|
}
|
|
|
|
if array.RebuildPercent != 42.5 {
|
|
t.Errorf("RebuildPercent = %f, want 42.5", array.RebuildPercent)
|
|
}
|
|
if array.RebuildSpeed != "50000K/sec" {
|
|
t.Errorf("RebuildSpeed = %q, want 50000K/sec", array.RebuildSpeed)
|
|
}
|
|
}
|
|
|
|
func TestReport_WithDisksAndNetwork(t *testing.T) {
|
|
report := Report{
|
|
Disks: []Disk{
|
|
{Device: "/dev/sda1", Mountpoint: "/", TotalBytes: 500000000000},
|
|
{Device: "/dev/sdb1", Mountpoint: "/data", TotalBytes: 1000000000000},
|
|
},
|
|
Network: []NetworkInterface{
|
|
{Name: "eth0", RXBytes: 1000000, TXBytes: 500000},
|
|
{Name: "eth1", RXBytes: 2000000, TXBytes: 1000000},
|
|
},
|
|
}
|
|
|
|
if len(report.Disks) != 2 {
|
|
t.Errorf("Disks count = %d, want 2", len(report.Disks))
|
|
}
|
|
if len(report.Network) != 2 {
|
|
t.Errorf("Network count = %d, want 2", len(report.Network))
|
|
}
|
|
}
|
|
|
|
func TestReport_WithSensorsAndRAID(t *testing.T) {
|
|
report := Report{
|
|
Sensors: Sensors{
|
|
TemperatureCelsius: map[string]float64{"cpu": 45.0},
|
|
},
|
|
RAID: []RAIDArray{
|
|
{Device: "/dev/md0", Level: "raid1", State: "clean"},
|
|
},
|
|
}
|
|
|
|
if len(report.Sensors.TemperatureCelsius) != 1 {
|
|
t.Errorf("TemperatureCelsius count = %d, want 1", len(report.Sensors.TemperatureCelsius))
|
|
}
|
|
if len(report.RAID) != 1 {
|
|
t.Errorf("RAID count = %d, want 1", len(report.RAID))
|
|
}
|
|
}
|
|
|
|
func TestReport_Tags(t *testing.T) {
|
|
report := Report{
|
|
Tags: []string{"production", "web", "us-east"},
|
|
}
|
|
|
|
if len(report.Tags) != 3 {
|
|
t.Errorf("Tags count = %d, want 3", len(report.Tags))
|
|
}
|
|
if report.Tags[0] != "production" {
|
|
t.Errorf("Tags[0] = %q, want production", report.Tags[0])
|
|
}
|
|
}
|
|
|
|
func TestReport_JSONOmitEmpty(t *testing.T) {
|
|
// Test that empty fields are omitted in JSON
|
|
report := Report{
|
|
Agent: AgentInfo{ID: "agent-1"},
|
|
Host: HostInfo{Hostname: "myhost"},
|
|
}
|
|
|
|
data, err := json.Marshal(report)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal: %v", err)
|
|
}
|
|
|
|
jsonStr := string(data)
|
|
|
|
// These should not appear in JSON when empty
|
|
if contains(jsonStr, `"disks":[]`) {
|
|
t.Error("Empty disks should be omitted")
|
|
}
|
|
if contains(jsonStr, `"network":[]`) {
|
|
t.Error("Empty network should be omitted")
|
|
}
|
|
if contains(jsonStr, `"tags":[]`) {
|
|
t.Error("Empty tags should be omitted")
|
|
}
|
|
}
|
|
|
|
// Helper function
|
|
func contains(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|