Files
l-ui/internal/util/sys/memlimit_agent_test.go
T

106 lines
3.3 KiB
Go

package sys
import (
"os"
"runtime/debug"
"strings"
"testing"
)
// lookupGOGC reports whether a GOGC env is present at all: presence
// (even empty handling aside) makes the tuning defer to the runtime,
// which the default-profile tests cannot exercise.
func lookupGOGC() (string, bool) {
return os.LookupEnv("GOGC")
}
// The agent tuning profile (ITEM-P3 A1): GOGC default 50 and a
// 24 MiB default soft budget, with explicit env budgets still
// winning. The runtime knobs are process-global, so each test
// restores whatever GC percent / memory limit it found.
func preserveRuntimeKnobs(t *testing.T) {
t.Helper()
prevGC := debug.SetGCPercent(-1)
prevLimit := debug.SetMemoryLimit(-1)
t.Cleanup(func() {
debug.SetGCPercent(prevGC)
debug.SetMemoryLimit(prevLimit)
})
}
func unsetenv(t *testing.T, keys ...string) {
t.Helper()
for _, k := range keys {
t.Setenv(k, "")
// t.Setenv cannot unset; an empty value is what the tuning
// code treats as absent (it trims before checking), except
// for GOGC where LookupEnv counts presence — see the GOGC
// case below, which is exercised only via XUI_GOGC instead.
}
}
func TestApplyAgentMemoryTuningDefaults(t *testing.T) {
preserveRuntimeKnobs(t)
unsetenv(t, "GOMEMLIMIT", "XUI_MEMORY_LIMIT", "XUI_GOGC")
if _, present := lookupGOGC(); present {
t.Skip("GOGC is set in the test environment")
}
lines := ApplyAgentMemoryTuning()
joined := strings.Join(lines, "\n")
if !strings.Contains(joined, "GC percent set to 50") {
t.Fatalf("lines = %v, want GC percent 50", lines)
}
if !strings.Contains(joined, "Go memory soft limit set to 24 MiB (agent default budget)") {
t.Fatalf("lines = %v, want 24 MiB agent default budget", lines)
}
if got := debug.SetMemoryLimit(-1); got != int64(24)<<20 {
t.Fatalf("memory limit = %d, want %d", got, int64(24)<<20)
}
if got := debug.SetGCPercent(-1); got != 50 {
t.Fatalf("GC percent = %d, want 50", got)
}
}
func TestApplyAgentMemoryTuningExplicitLimitWins(t *testing.T) {
preserveRuntimeKnobs(t)
unsetenv(t, "GOMEMLIMIT")
t.Setenv("XUI_MEMORY_LIMIT", "40")
lines := ApplyAgentMemoryTuning()
if !strings.Contains(strings.Join(lines, "\n"), "Go memory soft limit set to 40 MiB (XUI_MEMORY_LIMIT=40MiB)") {
t.Fatalf("lines = %v, want XUI_MEMORY_LIMIT budget", lines)
}
if got := debug.SetMemoryLimit(-1); got != int64(40)<<20 {
t.Fatalf("memory limit = %d, want %d", got, int64(40)<<20)
}
}
func TestApplyAgentMemoryTuningGOMEMLIMITEnvWins(t *testing.T) {
preserveRuntimeKnobs(t)
before := debug.SetMemoryLimit(-1)
t.Setenv("GOMEMLIMIT", "32MiB")
lines := ApplyAgentMemoryTuning()
if !strings.Contains(strings.Join(lines, "\n"), "Go memory soft limit not enforced: GOMEMLIMIT env") {
t.Fatalf("lines = %v, want GOMEMLIMIT left to the runtime", lines)
}
if got := debug.SetMemoryLimit(-1); got != before {
t.Fatalf("memory limit changed to %d, want untouched %d", got, before)
}
}
func TestApplyAgentMemoryTuningXUIGOGCOverride(t *testing.T) {
preserveRuntimeKnobs(t)
if _, present := lookupGOGC(); present {
t.Skip("GOGC is set in the test environment")
}
t.Setenv("XUI_GOGC", "80")
lines := ApplyAgentMemoryTuning()
if !strings.Contains(strings.Join(lines, "\n"), "GC percent set to 80") {
t.Fatalf("lines = %v, want XUI_GOGC override", lines)
}
}