Publish ITWorx Pulse source
Public source validation / validate (push) Failing after 3m8s

This commit is contained in:
ITWorx Pulse release export
2026-09-03 02:09:19 +02:00
commit bd774932d5
614 changed files with 77116 additions and 0 deletions
+199
View File
@@ -0,0 +1,199 @@
package hostcollect
import (
"os"
"path/filepath"
"testing"
)
func readFixture(t *testing.T, elements ...string) []byte {
t.Helper()
path := filepath.Join(append([]string{"testdata"}, elements...)...)
data, err := os.ReadFile(path) //nolint:gosec // fixture path is test-controlled
if err != nil {
t.Fatalf("read fixture %s: %v", path, err)
}
return data
}
func TestParseProcStatReadsAggregateAndCores(t *testing.T) {
sample, err := parseProcStat(readFixture(t, "proc-healthy", "stat"))
if err != nil {
t.Fatalf("parseProcStat returned error: %v", err)
}
// user+nice+system+idle+iowait+irq+softirq+steal, with guest and guest_nice left
// out because the kernel already counts guest time inside user and nice.
const wantTotal = 1234567 + 8901 + 234567 + 45678901 + 12345 + 0 + 6789 + 1234
if sample.all.total != wantTotal {
t.Fatalf("aggregate total = %d, want %d", sample.all.total, wantTotal)
}
if sample.all.idle != 45678901 || sample.all.iowait != 12345 {
t.Fatalf("unexpected idle/iowait: %+v", sample.all)
}
if len(sample.cores) != 2 {
t.Fatalf("cores = %d, want 2", len(sample.cores))
}
}
func TestParseProcStatToleratesOldKernelsAndGarbage(t *testing.T) {
sample, err := parseProcStat(readFixture(t, "proc-messy", "stat"))
if err != nil {
t.Fatalf("parseProcStat returned error: %v", err)
}
if sample.all.total != 1000+200+300+4000 {
t.Fatalf("unexpected total for a four column kernel: %d", sample.all.total)
}
// cpu0 and cpu2 parse; "cpu-bogus" and the non-numeric "cpu9" line do not.
if len(sample.cores) != 2 {
t.Fatalf("cores = %d, want 2", len(sample.cores))
}
}
func TestParseProcStatRequiresAggregate(t *testing.T) {
if _, err := parseProcStat([]byte("intr 1 2 3\nctxt 4\n")); err == nil {
t.Fatal("expected an error when /proc/stat has no cpu line")
}
}
func TestUtilisationComputesDeltaNotAbsoluteValue(t *testing.T) {
previous := cpuTimes{total: 1000, idle: 800, iowait: 100}
current := cpuTimes{total: 1200, idle: 900, iowait: 150}
busy, iowait, ok := utilisation(previous, current)
if !ok {
t.Fatal("expected a usable delta")
}
if busy != 25 {
t.Fatalf("busy = %v, want 25", busy)
}
if iowait != 25 {
t.Fatalf("iowait = %v, want 25", iowait)
}
}
func TestUtilisationRejectsCounterWrapAndStandstill(t *testing.T) {
cases := map[string]struct{ previous, current cpuTimes }{
"total wrapped": {cpuTimes{total: 18446744073709551000, idle: 10, iowait: 1}, cpuTimes{total: 400, idle: 20, iowait: 2}},
"idle wrapped": {cpuTimes{total: 1000, idle: 900, iowait: 10}, cpuTimes{total: 1100, idle: 5, iowait: 11}},
"iowait wrapped": {cpuTimes{total: 1000, idle: 800, iowait: 100}, cpuTimes{total: 1100, idle: 850, iowait: 4}},
"no elapsed": {cpuTimes{total: 1000, idle: 800, iowait: 100}, cpuTimes{total: 1000, idle: 800, iowait: 100}},
"idle exceeds": {cpuTimes{total: 1000, idle: 800, iowait: 100}, cpuTimes{total: 1010, idle: 900, iowait: 120}},
}
for name, testCase := range cases {
t.Run(name, func(t *testing.T) {
if _, _, ok := utilisation(testCase.previous, testCase.current); ok {
t.Fatal("expected the delta to be rejected as unusable")
}
})
}
}
func TestParseMeminfoConvertsKibibytes(t *testing.T) {
memory, err := parseMeminfo(readFixture(t, "proc-healthy", "meminfo"))
if err != nil {
t.Fatalf("parseMeminfo returned error: %v", err)
}
if memory.TotalBytes != 32819484*1024 {
t.Fatalf("total = %d, want %d", memory.TotalBytes, 32819484*1024)
}
if memory.AvailableBytes != 24680240*1024 {
t.Fatalf("available = %d", memory.AvailableBytes)
}
if memory.SwapTotalBytes != 8388604*1024 || memory.SwapUsedBytes != (8388604-8000000)*1024 {
t.Fatalf("unexpected swap: %+v", memory)
}
}
func TestParseMeminfoFallsBackWhenMemAvailableIsAbsent(t *testing.T) {
memory, err := parseMeminfo(readFixture(t, "proc-messy", "meminfo"))
if err != nil {
t.Fatalf("parseMeminfo returned error: %v", err)
}
want := uint64(123456+23456+2000000+100000) * 1024
if memory.AvailableBytes != want {
t.Fatalf("available = %d, want %d", memory.AvailableBytes, want)
}
if memory.SwapTotalBytes != 0 || memory.SwapUsedBytes != 0 {
t.Fatalf("swapless host reported swap: %+v", memory)
}
}
func TestParseMeminfoRequiresMemTotal(t *testing.T) {
if _, err := parseMeminfo([]byte("MemFree: 100 kB\n")); err == nil {
t.Fatal("expected an error without MemTotal")
}
}
func TestParseLoadAverage(t *testing.T) {
load, err := parseLoadAverage(readFixture(t, "proc-healthy", "loadavg"))
if err != nil {
t.Fatalf("parseLoadAverage returned error: %v", err)
}
if load.One != 1.52 || load.Five != 2.08 || load.Fifteen != 2.35 {
t.Fatalf("unexpected load: %+v", load)
}
for _, malformed := range []string{"not-a-load\n", "1.0 2.0\n", "-1 2 3\n", ""} {
if _, err := parseLoadAverage([]byte(malformed)); err == nil {
t.Fatalf("expected an error for %q", malformed)
}
}
}
func TestParseUptime(t *testing.T) {
seconds, err := parseUptime(readFixture(t, "proc-healthy", "uptime"))
if err != nil {
t.Fatalf("parseUptime returned error: %v", err)
}
if seconds != 351282.31 {
t.Fatalf("uptime = %v", seconds)
}
for _, malformed := range []string{"", "nonsense\n", "-5 10\n", "999999999999 1\n"} {
if _, err := parseUptime([]byte(malformed)); err == nil {
t.Fatalf("expected an error for %q", malformed)
}
}
}
func TestParseNetDevHandlesMissingSpaceAfterColon(t *testing.T) {
interfaces := parseNetDev(readFixture(t, "proc-healthy", "net", "dev"))
byName := map[string]uint64{}
for _, item := range interfaces {
byName[item.Name] = item.RxBytes
}
// eth0's receive counter runs straight into the colon in the fixture.
if byName["eth0"] != 18446744073709551615 {
t.Fatalf("eth0 rx = %d", byName["eth0"])
}
if _, present := byName["wlan0"]; present {
t.Fatal("a row with a non-numeric counter must be dropped, not zeroed")
}
if _, present := byName["tap0"]; present {
t.Fatal("a truncated row must be dropped")
}
if len(interfaces) != 3 {
t.Fatalf("interfaces = %d, want lo, eth0 and br0", len(interfaces))
}
for _, item := range interfaces {
if item.Name == "eth0" && (item.RxErrors != 12 || item.RxDrops != 3 || item.TxErrors != 1 || item.TxDrops != 7) {
t.Fatalf("unexpected eth0 error counters: %+v", item)
}
}
}
func TestParseMountsUnescapesOctalSequences(t *testing.T) {
entries := parseMounts(readFixture(t, "proc-healthy", "mounts"))
found := false
for _, entry := range entries {
if entry.mount == "/mnt/disks/Media Backup" {
found = true
if entry.fsType != "btrfs" {
t.Fatalf("unexpected fs type: %q", entry.fsType)
}
}
}
if !found {
t.Fatal("expected the escaped mount point to be decoded")
}
if len(entries) != 12 {
t.Fatalf("entries = %d, want 12", len(entries))
}
}