libs/memory-budgeter.test.lua

96 lines

1#!/usr/bin/env luajit
2-- {{{ memory-budgeter.test.lua
3-- Issue 10-057: unit tests for the memory budgeter.
4--
5-- The pure compute_fit() cases use headroom 0.5 (binary-exact) so floating point
6-- cannot nudge an expected worker count off by one at a boundary. (In real use the
7-- default 0.7 headroom means an exact boundary rounds DOWN -- conservative, i.e. one
8-- fewer worker -- which is the safe direction for a memory budget, so it is fine.)
9-- A light smoke test exercises the live RAM probe and file sizing.
10--
11-- Run: luajit libs/memory-budgeter.test.lua [DIR]
12-- }}}
13
14local DIR = arg[1] or "/mnt/mtwo/programming/ai-stuff/neocities-modernization"
15package.path = DIR .. "/libs/?.lua;" .. DIR .. "/src/?.lua;" .. package.path
16
17local budget = require("memory-budgeter")
18
19local GB = 1e9
20local passed, failed = 0, 0
21-- {{{ check()
22local function check(name, cond)
23 if cond then
24 passed = passed + 1
25 else
26 failed = failed + 1
27 print(" FAIL: " .. name)
28 end
29end
30-- }}}
31
32-- 1. Plenty of room: the requested count survives unchanged.
33do
34 local f = budget.compute_fit(60*GB, 2*GB, 0.05*GB, 8, 0.5) -- budget 30GB
35 check("comfortable: keeps want", f.threads == 8)
36 check("comfortable: not reduced", f.reduced == false)
37 check("comfortable: not swapping", f.swapping == false)
38end
39
40-- 2. Per-worker cost forces a reduction below the requested count.
41do
42 local f = budget.compute_fit(20*GB, 2*GB, 1*GB, 12, 0.5) -- budget 10GB; (10-2)/1 = 8
43 check("reduction: clamps to safe count", f.threads == 8)
44 check("reduction: flagged reduced", f.reduced == true)
45 check("reduction: not swapping", f.swapping == false)
46end
47
48-- 3. The shared (fixed) data alone overflows the budget: warn, 1 worker, no abort.
49do
50 local f = budget.compute_fit(20*GB, 12*GB, 0.5*GB, 8, 0.5) -- budget 10GB; fixed 12 > 10
51 check("swapping: returns 1 worker", f.threads == 1)
52 check("swapping: flagged", f.swapping == true)
53end
54
55-- 4. Zero per-worker cost: workers are free, so keep the count; swapping only on fixed.
56do
57 local f = budget.compute_fit(20*GB, 2*GB, 0, 16, 0.5) -- fixed fits
58 check("zero per-worker: keeps want", f.threads == 16)
59 check("zero per-worker: not swapping when fixed fits", f.swapping == false)
60 local g = budget.compute_fit(20*GB, 12*GB, 0, 16, 0.5) -- fixed overflows
61 check("zero per-worker: swaps when fixed overflows", g.swapping == true)
62 check("zero per-worker: count unchanged even when swapping", g.threads == 16)
63end
64
65-- 5. Exactly one worker fits (clear, non-fractional boundary).
66do
67 local f = budget.compute_fit(20*GB, 9*GB, 1*GB, 8, 0.5) -- budget 10GB; (10-9)/1 = 1
68 check("boundary: exactly one fits", f.threads == 1)
69 check("boundary: not swapping", f.swapping == false)
70end
71
72-- 6. A nonsensical request is floored to at least one worker.
73do
74 local f = budget.compute_fit(60*GB, 1*GB, 0.1*GB, 0, 0.5)
75 check("want floored to >= 1", f.threads == 1)
76end
77
78-- 7. Live RAM probe: fit_threads returns a sane count and never exceeds the request.
79do
80 local threads = budget.fit_threads({
81 pool = "ram", fixed = 1*GB, per_thread = 0.05*GB, want = 4, label = "selftest",
82 })
83 check("live: returns >= 1", threads >= 1)
84 check("live: never exceeds want", threads <= 4)
85end
86
87-- 8. file_size_bytes: positive on a real file, nil on a missing one.
88do
89 local self_size = budget.file_size_bytes(DIR .. "/libs/memory-budgeter.test.lua")
90 check("file size: positive on real file", self_size ~= nil and self_size > 0)
91 check("file size: nil on missing file", budget.file_size_bytes(DIR .. "/does-not-exist-xyz") == nil)
92end
93
94print(string.format("memory-budgeter: %d passed, %d failed", passed, failed))
95if failed > 0 then os.exit(1) end
96