a73x

internal/agent/hostinfo/hostinfo_linux_test.go

Ref:   Size: 3.9 KiB   History

//go:build linux

package hostinfo

import (
	"context"
	"errors"
	"runtime"
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
)

// These three tests stub sysinfoFn/statfsFn with syscall.Sysinfo_t/Statfs_t
// literals, which only exist on Linux — they live in this Linux-tagged file
// (rather than hostinfo_test.go) purely so the package still vets clean on
// other GOOS; the assertions are unchanged from before the per-OS split.

// TestCapacityExactArithmetic pins TOTALS (not free space): a regression that
// swaps in Bavail/Bfree or free-memory fields must fail this test, since the
// server derives available capacity by subtracting live VM specs from
// whatever Capacity reports.
func TestCapacityExactArithmetic(t *testing.T) {
	oldSys, oldStat := sysinfoFn, statfsFn
	defer func() { sysinfoFn, statfsFn = oldSys, oldStat }()

	sysinfoFn = func(si *syscall.Sysinfo_t) error {
		*si = syscall.Sysinfo_t{
			Totalram: 8 * 1024 * 1024 * 1024, // 8 GiB
			Unit:     1,
		}
		return nil
	}
	statfsFn = func(_ string, fs *syscall.Statfs_t) error {
		*fs = syscall.Statfs_t{
			Bsize:  4096,
			Blocks: 26214400, // 100 GiB total
		}
		return nil
	}

	c := Capacity("/whatever")
	assert.Equal(t, int64(runtime.NumCPU()), c.GetVcpus())
	assert.Equal(t, int64(8192), c.GetMemMb())
	assert.Equal(t, int64(100), c.GetDiskGb())
}

// TestCapacityBestEffortOnSyscallFailure covers the package's best-effort
// contract: a failing probe zeroes its own dimension rather than erroring or
// blocking, and the two probes fail independently of each other.
func TestCapacityBestEffortOnSyscallFailure(t *testing.T) {
	oldSys, oldStat := sysinfoFn, statfsFn
	defer func() { sysinfoFn, statfsFn = oldSys, oldStat }()

	sysinfoFn = func(*syscall.Sysinfo_t) error { return errors.New("boom") }
	statfsFn = func(_ string, fs *syscall.Statfs_t) error {
		*fs = syscall.Statfs_t{Bsize: 4096, Blocks: 26214400}
		return nil
	}
	c := Capacity("/whatever")
	assert.Equal(t, int64(0), c.GetMemMb())
	assert.Equal(t, int64(100), c.GetDiskGb())

	sysinfoFn = func(si *syscall.Sysinfo_t) error {
		*si = syscall.Sysinfo_t{Totalram: 8 * 1024 * 1024 * 1024, Unit: 1}
		return nil
	}
	statfsFn = func(_ string, _ *syscall.Statfs_t) error { return errors.New("boom") }
	c = Capacity("/whatever")
	assert.Equal(t, int64(8192), c.GetMemMb())
	assert.Equal(t, int64(0), c.GetDiskGb())
}

// TestFactsVirtComesFromTheRunner keeps the Linux virt expectation with the
// platform that has it: Facts asks systemd-detect-virt through the injected
// runner. Darwin answers "none" without a subprocess (hostinfo_darwin_test.go).
func TestFactsVirtComesFromTheRunner(t *testing.T) {
	f := Facts(context.Background(), func(_ context.Context, _ string, _ ...string) (string, error) {
		return "kvm\n", nil
	})
	assert.Equal(t, "kvm", f.GetVirt())
}

func TestMetricsComputes(t *testing.T) {
	oldSys, oldStat, oldMem := sysinfoFn, statfsFn, memInfoPath
	defer func() { sysinfoFn, statfsFn, memInfoPath = oldSys, oldStat, oldMem }()

	sysinfoFn = func(si *syscall.Sysinfo_t) error {
		*si = syscall.Sysinfo_t{
			Uptime:   3600,
			Loads:    [3]uint64{65536, 32768, 0}, // 1.0, 0.5, 0.0
			Totalram: 8 * 1024 * 1024 * 1024,     // 8 GiB
			Unit:     1,
		}
		return nil
	}
	memInfoPath = writeFixture(t, "meminfo", "MemTotal: 8388608 kB\nMemAvailable: 4194304 kB\n") // 4 GiB avail
	statfsFn = func(_ string, fs *syscall.Statfs_t) error {
		*fs = syscall.Statfs_t{
			Bsize:  4096,
			Blocks: 26214400, // 100 GiB total
			Bfree:  13107200, // 50 GiB free (incl reserved)
			Bavail: 10485760, // 40 GiB avail to non-root
		}
		return nil
	}

	m := Metrics("/whatever")
	assert.Equal(t, int64(3600), m.GetUptimeS())
	assert.InDelta(t, 1.0, m.GetLoad1(), 0.001)
	assert.InDelta(t, 0.5, m.GetLoad5(), 0.001)
	assert.Equal(t, int64(4096), m.GetMemAvailableMb())
	assert.Equal(t, int64(4096), m.GetMemUsedMb()) // 8192 total − 4096 avail
	assert.Equal(t, int64(40), m.GetDiskFreeGb())
	assert.Equal(t, int64(50), m.GetDiskUsedGb()) // (Blocks − Bfree) × Bsize
}