Files
zzet--gortex/cmd/gortex/daemon_memlimit_test.go
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

179 lines
5.8 KiB
Go

package main
import (
"runtime"
"testing"
"go.uber.org/zap"
)
const (
kib = int64(1) << 10
mib = int64(1) << 20
gib = int64(1) << 30
tib = int64(1) << 40
)
func TestParseByteSize(t *testing.T) {
tests := []struct {
in string
want int64
wantErr bool
}{
{"", 0, false},
{"0", 0, false},
{"off", 0, false},
{"OFF", 0, false},
{" off ", 0, false},
{"1024", 1024, false}, // bare number = bytes
{"1B", 1, false},
{"1KiB", kib, false},
{"1kb", kib, false}, // KB treated as binary (memory budget)
{"2K", 2 * kib, false},
{"4096MiB", 4096 * mib, false}, // == 4 GiB
{"4GiB", 4 * gib, false},
{"2G", 2 * gib, false},
{"2gb", 2 * gib, false},
{"1T", tib, false},
{"1TiB", tib, false},
{"nonsense", 0, true},
{"12x", 0, true}, // unknown unit
{"GiB", 0, true}, // no number
{"-5GiB", 0, true}, // negative
{"99999999999999999999G", 0, true}, // overflow
}
for _, tc := range tests {
got, err := parseByteSize(tc.in)
if tc.wantErr {
if err == nil {
t.Errorf("parseByteSize(%q): expected error, got %d", tc.in, got)
}
continue
}
if err != nil {
t.Errorf("parseByteSize(%q): unexpected error %v", tc.in, err)
continue
}
if got != tc.want {
t.Errorf("parseByteSize(%q) = %d, want %d", tc.in, got, tc.want)
}
}
}
func TestDefaultStandingMemoryLimit(t *testing.T) {
tests := []struct {
name string
hostRAM uint64
want int64
}{
{"unknown host RAM => 0", 0, 0},
{"tiny host clamps up to floor", uint64(2) * uint64(gib), standingMemLimitFloor}, // 2GiB/4=512MiB -> 1GiB
{"mid host uses quarter", uint64(16) * uint64(gib), 4 * gib}, // 16GiB/4=4GiB
{"large host clamps down to ceil", uint64(64) * uint64(gib), standingMemLimitCeil}, // 64GiB/4=16GiB -> 8GiB
{"exactly floor boundary", uint64(4) * uint64(gib), gib}, // 4GiB/4=1GiB
{"exactly ceil boundary", uint64(32) * uint64(gib), 8 * gib}, // 32GiB/4=8GiB
}
for _, tc := range tests {
if got := defaultStandingMemoryLimit(tc.hostRAM); got != tc.want {
t.Errorf("%s: defaultStandingMemoryLimit(%d) = %d, want %d", tc.name, tc.hostRAM, got, tc.want)
}
}
}
func TestResolveStandingMemoryLimit(t *testing.T) {
const host = uint64(16) * uint64(1<<30) // 16 GiB -> default 4 GiB
tests := []struct {
name string
hostRAM uint64
goenv string
env string
cfg string
wantLimit int64
wantSource string
wantWarn bool
}{
{"GOMEMLIMIT wins, install nothing", host, "5GiB", "4GiB", "2GiB", 0, "goenv", false},
{"GOMEMLIMIT wins even when malformed-looking", host, "someval", "4GiB", "", 0, "goenv", false},
{"env value honored verbatim", host, "", "6GiB", "2GiB", 6 * gib, "env", false},
{"env off disables", host, "", "off", "2GiB", 0, "off", false},
{"env zero disables", host, "", "0", "2GiB", 0, "off", false},
{"config used when env empty", host, "", "", "3GiB", 3 * gib, "config", false},
{"config off disables", host, "", "", "off", 0, "off", false},
{"default when nothing set", host, "", "", "", 4 * gib, "default", false},
{"malformed env falls back to default with warning", host, "", "bogus", "2GiB", 4 * gib, "default", true},
{"malformed config falls back to default with warning", host, "", "", "bogus", 4 * gib, "default", true},
{"default clamps up on tiny host", uint64(2) * uint64(gib), "", "", "", standingMemLimitFloor, "default", false},
{"default clamps down on large host", uint64(128) * uint64(gib), "", "", "", standingMemLimitCeil, "default", false},
{"unknown host and no explicit value", 0, "", "", "", 0, "unavailable", false},
}
for _, tc := range tests {
got := resolveStandingMemoryLimit(tc.hostRAM, tc.goenv, tc.env, tc.cfg)
if got.limit != tc.wantLimit || got.source != tc.wantSource {
t.Errorf("%s: resolve(...) = {limit:%d, source:%q}, want {limit:%d, source:%q}",
tc.name, got.limit, got.source, tc.wantLimit, tc.wantSource)
}
if (got.warn != "") != tc.wantWarn {
t.Errorf("%s: warn=%q, wantWarn=%v", tc.name, got.warn, tc.wantWarn)
}
}
}
func TestMemReleaseEnabled(t *testing.T) {
tests := []struct {
val string
want bool
}{
{"", true}, // unset => on by default
{"1", true},
{"true", true},
{"anything", true},
{"0", false}, // kill-switch
{"false", false},
{"FALSE", false},
}
for _, tc := range tests {
t.Setenv("GORTEX_DAEMON_MEMRELEASE", tc.val)
if got := memReleaseEnabled(); got != tc.want {
t.Errorf("memReleaseEnabled() with %q = %v, want %v", tc.val, got, tc.want)
}
}
}
func TestReleaseMemoryToOS_KillSwitch(t *testing.T) {
// With the kill-switch set, the helper must be a no-op: it must not
// panic and must return without forcing a collection. We can only
// observe "no crash / returns" here; the enablement predicate is
// covered exhaustively by TestMemReleaseEnabled.
t.Setenv("GORTEX_DAEMON_MEMRELEASE", "0")
releaseMemoryToOS(zap.NewNop(), "kill-switch-test")
}
func TestReleaseMemoryToOS_Smoke(t *testing.T) {
t.Setenv("GORTEX_DAEMON_MEMRELEASE", "1")
// Allocate then drop a chunk so there is heap for the forced scavenge
// to return, then confirm HeapReleased did not go backwards across the
// call. Exact byte counts are intentionally not asserted.
sink := make([]byte, 8<<20)
for i := range sink {
sink[i] = byte(i)
}
// Force the writes to land (so the allocation is not elided), then let the
// reference drop here: sink is dead past this point, so the scavenge below
// has heap to return.
runtime.KeepAlive(sink)
var before runtime.MemStats
runtime.ReadMemStats(&before)
releaseMemoryToOS(zap.NewNop(), "smoke-test")
var after runtime.MemStats
runtime.ReadMemStats(&after)
if after.HeapReleased < before.HeapReleased {
t.Fatalf("HeapReleased went backwards after FreeOSMemory: before=%d after=%d",
before.HeapReleased, after.HeapReleased)
}
}