You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
4.0 KiB

package systemmetrics
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"tera-clone/services/tera-api/internal/domain"
)
func TestLinuxReaderCollectsBoundedDashboardMetrics(t *testing.T) {
root := t.TempDir()
procRoot := filepath.Join(root, "proc")
sysRoot := filepath.Join(root, "sys")
etcRoot := filepath.Join(root, "etc")
writeMetricFile(t, filepath.Join(procRoot, "uptime"), "93784.9 0\n")
writeMetricFile(t, filepath.Join(procRoot, "loadavg"), "0.46 0.45 0.41 1/100 10\n")
writeMetricFile(t, filepath.Join(procRoot, "stat"), "cpu 100 0 50 850 0 0 0 0\n")
writeMetricFile(t, filepath.Join(procRoot, "meminfo"), "MemTotal: 2048000 kB\nMemFree: 256000 kB\nMemAvailable: 512000 kB\nBuffers: 64000 kB\nCached: 128000 kB\n")
writeMetricFile(t, filepath.Join(sysRoot, "class", "thermal", "thermal_zone0", "temp"), "53800\n")
writeMetricFile(t, filepath.Join(etcRoot, "tera", "build-number"), "N010-0020-2609-0062\n")
writeMetricFile(t, filepath.Join(etcRoot, "machine-id"), "device-4027\n")
interfaceRoot := filepath.Join(sysRoot, "class", "net", "eth0")
writeMetricFile(t, filepath.Join(interfaceRoot, "address"), "6c:b3:50:0d:36:12\n")
writeMetricFile(t, filepath.Join(interfaceRoot, "operstate"), "up\n")
writeMetricFile(t, filepath.Join(interfaceRoot, "speed"), "1000\n")
writeMetricFile(t, filepath.Join(interfaceRoot, "statistics", "rx_bytes"), "12345\n")
writeMetricFile(t, filepath.Join(interfaceRoot, "statistics", "tx_bytes"), "67890\n")
now := time.Date(2026, 8, 14, 12, 0, 0, 0, time.UTC)
reader := NewLinuxReader(LinuxReaderOptions{ProcRoot: procRoot, SysRoot: sysRoot, EtcRoot: etcRoot, Clock: func() time.Time { return now }})
interfaces := []domain.NetworkInterface{{Name: "Interface-1", Device: "eth0", Address: "192.168.0.223/24", IPv6Address: "fe80::1/64"}}
first := reader.Read(context.Background(), interfaces)
if first.CPUUsagePercent != nil {
t.Fatalf("first CPU sample = %v, want nil baseline", *first.CPUUsagePercent)
}
writeMetricFile(t, filepath.Join(procRoot, "stat"), "cpu 150 0 50 900 0 0 0 0\n")
metrics := reader.Read(context.Background(), interfaces)
if metrics.BuildNumber != "N010-0020-2609-0062" || metrics.DeviceID != "device-4027" || metrics.UptimeSeconds != 93784 || !metrics.SystemTime.Equal(now) {
t.Fatalf("identity/runtime metrics = %+v", metrics)
}
if metrics.TemperatureCelsius == nil || *metrics.TemperatureCelsius != 53.8 || metrics.CPUUsagePercent == nil || *metrics.CPUUsagePercent != 50 {
t.Fatalf("temperature/CPU metrics = %+v", metrics)
}
if len(metrics.LoadAverages) != 3 || metrics.LoadAverages[2] != 0.41 {
t.Fatalf("load averages = %v", metrics.LoadAverages)
}
if metrics.MemoryTotalBytes != 2097152000 || metrics.MemoryAvailableBytes != 524288000 || metrics.MemoryUsedBytes != 1572864000 || metrics.MemoryUsagePercent == nil || *metrics.MemoryUsagePercent != 75 {
t.Fatalf("memory metrics = %+v", metrics)
}
if len(metrics.NetworkInterfaces) != 1 {
t.Fatalf("interfaces = %+v", metrics.NetworkInterfaces)
}
item := metrics.NetworkInterfaces[0]
if item.MACAddress != "6c:b3:50:0d:36:12" || item.Link != "up" || item.SpeedMbps != 1000 || item.RXBytes != 12345 || item.TXBytes != 67890 || len(item.Addresses) != 2 {
t.Fatalf("network metrics = %+v", item)
}
}
func TestLinuxReaderRejectsUnsafeInterfaceDevicePath(t *testing.T) {
root := t.TempDir()
reader := NewLinuxReader(LinuxReaderOptions{ProcRoot: root, SysRoot: root, EtcRoot: root})
metrics := reader.Read(context.Background(), []domain.NetworkInterface{{Name: "Interface-1", Device: "../secret", Link: "down"}})
if len(metrics.NetworkInterfaces) != 1 || metrics.NetworkInterfaces[0].MACAddress != "" || metrics.NetworkInterfaces[0].Link != "down" {
t.Fatalf("unsafe device result = %+v", metrics.NetworkInterfaces)
}
}
func writeMetricFile(t *testing.T, path, content string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
}