A module is for any mesh; the check reads the list of names at the root and the covered modules, and the kernel module's fixtures now say what they show.
114 lines
5.0 KiB
Go
114 lines
5.0 KiB
Go
package main
|
|
|
|
// Over a stand-in tree holding the files of a real machine of 2026-10-14 23:25 (read through node-reads for
|
|
// novox/hq issue 746): the mode, the per-size controls, meminfo's huge page lines, and fail2ban's and
|
|
// journald's memory.stat and io.stat, cut to the lines the tool reads.
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func tree(t *testing.T, files map[string]string) *Machine {
|
|
t.Helper()
|
|
root := t.TempDir()
|
|
for p, content := range files {
|
|
full := filepath.Join(root, p)
|
|
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(full, []byte(content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return &Machine{Root: root}
|
|
}
|
|
|
|
func capturedMachine(t *testing.T) *Machine {
|
|
thp := "sys/kernel/mm/transparent_hugepage/"
|
|
cg := "sys/fs/cgroup/system.slice/"
|
|
files := map[string]string{
|
|
thp + "enabled": "[always] madvise never\n",
|
|
thp + "defrag": "always defer defer+madvise [madvise] never\n",
|
|
thp + "shmem_enabled": "always within_size [advise] never deny force\n",
|
|
thp + "hugepages-2048kB/enabled": "always [inherit] madvise never\n",
|
|
thp + "hugepages-64kB/enabled": "always inherit madvise [never]\n",
|
|
thp + "hugepages-1024kB/enabled": "always inherit madvise [never]\n",
|
|
"proc/meminfo": "MemTotal: 65748808 kB\nAnonHugePages: 3579904 kB\nShmemHugePages: 4096 kB\n" +
|
|
"ShmemPmdMapped: 4096 kB\nFileHugePages: 1693696 kB\nFilePmdMapped: 882688 kB\nHugepagesize: 2048 kB\n",
|
|
cg + "fail2ban.service/memory.stat": "anon 21815296\nfile 204623872\nfile_mapped 130736128\nfile_dirty 27262976\n" +
|
|
"file_writeback 4096\nanon_thp 0\nfile_thp 197132288\nthp_fault_alloc 0\nthp_collapse_alloc 550\n",
|
|
cg + "fail2ban.service/io.stat": "9:0 \n8:16 rbytes=3223552 wbytes=67723415552 rios=240 wios=281159 dbytes=0 dios=0\n" +
|
|
"8:0 rbytes=6152192 wbytes=67723415552 rios=832 wios=281159 dbytes=0 dios=0\n" +
|
|
"9:2 rbytes=9375744 wbytes=67723415552 rios=1072 wios=281159 dbytes=0 dios=0\n",
|
|
cg + "systemd-journald.service/memory.stat": "anon 3227648\nfile 1032015872\nfile_mapped 131928064\nfile_dirty 622592\n" +
|
|
"file_writeback 159744\nanon_thp 2097152\nfile_thp 379584512\nthp_fault_alloc 0\nthp_collapse_alloc 11741\n",
|
|
cg + "systemd-journald.service/io.stat": "9:0 \n8:16 rbytes=55209984 wbytes=2498768035840 rios=1317 wios=24719004 dbytes=0 dios=0\n" +
|
|
"8:0 rbytes=72953856 wbytes=2498768039936 rios=2194 wios=24719005 dbytes=0 dios=0\n" +
|
|
"9:2 rbytes=128163840 wbytes=2498724843520 rios=3511 wios=24707873 dbytes=0 dios=0\n",
|
|
cg + "sshd.service/memory.stat": "anon 1000\nfile_thp 0\n",
|
|
}
|
|
return tree(t, files)
|
|
}
|
|
|
|
func TestTheCapturedMachineBeforeTheChange(t *testing.T) {
|
|
a, err := capturedMachine(t).HugePages(10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a.Mode != "always" || a.Defrag != "madvise" || a.Shmem != "advise" {
|
|
t.Fatalf("modes: %+v", a)
|
|
}
|
|
if len(a.PerSize) != 3 || a.PerSize[0].Size != "64kB" || a.PerSize[2].Size != "2048kB" ||
|
|
a.PerSize[2].Enabled != "inherit" || a.PerSize[2].Means != "always" || a.PerSize[0].Means != "never" {
|
|
t.Fatalf("per size: %+v", a.PerSize)
|
|
}
|
|
if a.Meminfo["FileHugePages"] != 1654 || a.Meminfo["FilePmdMapped"] != 862 {
|
|
t.Fatalf("meminfo: %v", a.Meminfo)
|
|
}
|
|
if len(a.Units) != 2 || a.Units[0].Cgroup != "system.slice/systemd-journald.service" ||
|
|
a.Units[1].Cgroup != "system.slice/fail2ban.service" {
|
|
t.Fatalf("units: %+v", a.Units)
|
|
}
|
|
// The mirror and its two members each count the write: the most any one saw, never their sum.
|
|
if a.Units[1].Written != 67723415552 || a.Units[1].FileTHP != 197132288 || a.Units[1].CollapsedByKhug != 550 {
|
|
t.Fatalf("fail2ban: %+v", a.Units[1])
|
|
}
|
|
said := strings.Join(a.Said, "\n")
|
|
for _, want := range []string{"transparent huge pages: always, defrag madvise", "sizes not never: 2048kB always",
|
|
"file 1654 MiB (mapped at 2 MiB 862 MiB)", "system.slice/fail2ban.service: file in huge folios 188.0 MiB"} {
|
|
if !strings.Contains(said, want) {
|
|
t.Errorf("said lacks %q:\n%s", want, said)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnitsAreBoundedAndNoneIsSaid(t *testing.T) {
|
|
a, err := capturedMachine(t).HugePages(1)
|
|
if err != nil || len(a.Units) != 1 {
|
|
t.Fatalf("%v %+v", err, a)
|
|
}
|
|
b, err := tree(t, map[string]string{"sys/kernel/mm/transparent_hugepage/enabled": "always [madvise] never\n"}).HugePages(10)
|
|
if err != nil || b.Mode != "madvise" || len(b.Units) != 0 || !strings.Contains(strings.Join(b.Said, "\n"), "no unit holds") {
|
|
t.Fatalf("%v %+v", err, b)
|
|
}
|
|
}
|
|
|
|
func TestAKernelWithoutHugePagesIsAnError(t *testing.T) {
|
|
if _, err := tree(t, map[string]string{"proc/meminfo": ""}).HugePages(10); err == nil ||
|
|
!strings.Contains(err.Error(), "built without transparent huge pages") {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
}
|
|
|
|
func TestTheArgumentIsBounded(t *testing.T) {
|
|
if _, err := whole(map[string]any{"units": -1.0}, "units", 10, 0, 100); err == nil {
|
|
t.Error("a negative count was accepted")
|
|
}
|
|
if n, _ := whole(map[string]any{"units": 1000.0}, "units", 10, 0, 100); n != 100 {
|
|
t.Errorf("not bounded: %d", n)
|
|
}
|
|
}
|