nx_budget_alloc_test.nx source
↩ module page · 129 lines · 5693 B
1// nx_budget_alloc_test.nx -- smoke for sovereign ceiling enforcement.
2//
3// Exercises:
4// 1. Allocations within budget succeed; ram_used increments correctly
5// 2. Allocation that WOULD exceed ceiling returns NULL; ram_used
6// unchanged (refusal BEFORE sys_mmap)
7// 3. Verdict-returning variant distinguishes OVER vs BAD_KIND vs OK
8// 4. release_logical decrements ram_used; subsequent allocations
9// succeed up to fresh headroom
10// 5. Multiple kinds enforce independently (RAM ceiling does not
11// block VRAM allocation and vice versa)
12// 6. Bad-input gates: null budget, zero size, negative size
13// 7. Sealed-enum verdict gate
14// 8. headroom() reflects state across allocations + releases
15//
16// Pure substrate: no /sys/fs/cgroup, no kernel cgroups, no Linux-
17// only assumptions. Same code path runs on every host.
18
19import "nx_syscalls.nx"
20import "nx_budget.nx"
21import "nx_budget_alloc.nx"
22
23func main() -> i64 {
24 // Budget: ram_max=1024, vram_max=2048, others=0 (won't allow
25 // any allocation of those kinds).
26 let b: *NxBudget = nx_budget_new(42, 1024, 2048, 0, 0, 0)
27
28 // ----- 1. Within-budget allocations succeed -----
29 let p1: *u8 = nx_budget_mmap(b, NX_RES_RAM, 512)
30 if (p1 as i64) == 0 { return 1 }
31 if b.ram_used != 512 { return 2 }
32 if nx_budget_alloc_remaining(b, NX_RES_RAM) != 512 { return 3 }
33
34 let p2: *u8 = nx_budget_mmap(b, NX_RES_RAM, 256)
35 if (p2 as i64) == 0 { return 4 }
36 if b.ram_used != 768 { return 5 }
37 if nx_budget_alloc_remaining(b, NX_RES_RAM) != 256 { return 6 }
38
39 // ----- 2. Over-budget allocation refused; state unchanged -----
40 // 512 more would put us at 1280, exceeding ram_max=1024.
41 let p_over: *u8 = nx_budget_mmap(b, NX_RES_RAM, 512)
42 if (p_over as i64) != 0 { return 7 } // NULL = refused
43 if b.ram_used != 768 { return 8 } // unchanged
44 if nx_budget_alloc_remaining(b, NX_RES_RAM) != 256 { return 9 }
45
46 // Even +1 more byte over the headroom is refused.
47 let p_over_tiny: *u8 = nx_budget_mmap(b, NX_RES_RAM, 257)
48 if (p_over_tiny as i64) != 0 { return 10 }
49 if b.ram_used != 768 { return 11 }
50
51 // ----- 3. Verdict-returning variant distinguishes failure modes -----
52 let verdict_slot: *i64 = (sys_mmap(8)) as *i64
53 *verdict_slot = -99
54
55 // Over-budget -> NX_BUDGET_ALLOC_OVER
56 let v_over: *u8 = nx_budget_mmap_with_verdict(b, NX_RES_RAM, 512, verdict_slot)
57 if (v_over as i64) != 0 { return 12 }
58 if *verdict_slot != NX_BUDGET_ALLOC_OVER { return 13 }
59 if b.ram_used != 768 { return 14 }
60
61 // OK case
62 let v_ok: *u8 = nx_budget_mmap_with_verdict(b, NX_RES_RAM, 100, verdict_slot)
63 if (v_ok as i64) == 0 { return 15 }
64 if *verdict_slot != NX_BUDGET_ALLOC_OK { return 16 }
65 if b.ram_used != 868 { return 17 }
66
67 // Bad-kind verdict
68 let v_bad: *u8 = nx_budget_mmap_with_verdict(b, 99, 64, verdict_slot)
69 if (v_bad as i64) != 0 { return 18 }
70 if *verdict_slot != NX_BUDGET_ALLOC_BAD_KIND { return 19 }
71
72 // Bad-input verdict
73 let null_b: *NxBudget = (0 as i64) as *NxBudget
74 let v_nb: *u8 = nx_budget_mmap_with_verdict(null_b, NX_RES_RAM, 64, verdict_slot)
75 if (v_nb as i64) != 0 { return 20 }
76 if *verdict_slot != NX_BUDGET_ALLOC_BAD_INPUT { return 21 }
77
78 // Zero-size
79 let v_zero: *u8 = nx_budget_mmap_with_verdict(b, NX_RES_RAM, 0, verdict_slot)
80 if (v_zero as i64) != 0 { return 22 }
81 if *verdict_slot != NX_BUDGET_ALLOC_BAD_INPUT { return 23 }
82
83 // ----- 4. release_logical decrements ram_used -----
84 if nx_budget_release_logical(b, NX_RES_RAM, 256) != NX_BUDGET_OK { return 24 }
85 if b.ram_used != 612 { return 25 } // 868 - 256
86
87 // Now an allocation that was previously over-budget succeeds.
88 let p_after_release: *u8 = nx_budget_mmap(b, NX_RES_RAM, 400)
89 if (p_after_release as i64) == 0 { return 26 }
90 if b.ram_used != 1012 { return 27 }
91
92 // ----- 5. Multiple kinds independent -----
93 // RAM is at 1012/1024 (12 headroom). VRAM is at 0/2048.
94 // VRAM allocation independent of RAM state.
95 let p_vram: *u8 = nx_budget_mmap(b, NX_RES_VRAM, 1024)
96 if (p_vram as i64) == 0 { return 28 }
97 if b.vram_used != 1024 { return 29 }
98 if b.ram_used != 1012 { return 30 } // unchanged
99
100 // Disk has max=0; ANY allocation refused.
101 let p_disk: *u8 = nx_budget_mmap(b, NX_RES_DISK, 1)
102 if (p_disk as i64) != 0 { return 31 }
103 if b.disk_used != 0 { return 32 }
104
105 // ----- 6. Bad-input gates (silent mode) -----
106 if (nx_budget_mmap(null_b, NX_RES_RAM, 64) as i64) != 0 { return 33 }
107 if (nx_budget_mmap(b, NX_RES_RAM, 0) as i64) != 0 { return 34 }
108 if (nx_budget_mmap(b, NX_RES_RAM, -1) as i64) != 0 { return 35 }
109 // Bad kind silent-mode
110 if (nx_budget_mmap(b, 99, 64) as i64) != 0 { return 36 }
111 if (nx_budget_mmap(b, -1, 64) as i64) != 0 { return 37 }
112 // State invariants preserved.
113 if b.ram_used != 1012 { return 38 }
114 if b.vram_used != 1024 { return 39 }
115
116 // ----- 7. Sealed-enum verdict gate -----
117 if nx_budget_alloc_verdict_is_valid(NX_BUDGET_ALLOC_OK) != 1 { return 40 }
118 if nx_budget_alloc_verdict_is_valid(NX_BUDGET_ALLOC_OVER) != 1 { return 41 }
119 if nx_budget_alloc_verdict_is_valid(-1) != 0 { return 42 }
120 if nx_budget_alloc_verdict_is_valid(NX_BUDGET_ALLOC_N) != 0 { return 43 }
121
122 // ----- 8. headroom reflects state -----
123 if nx_budget_alloc_remaining(b, NX_RES_RAM) != 12 { return 44 } // 1024 - 1012
124 if nx_budget_alloc_remaining(b, NX_RES_VRAM) != 1024 { return 45 } // 2048 - 1024
125 if nx_budget_alloc_remaining(b, NX_RES_DISK) != 0 { return 46 }
126 if nx_budget_alloc_remaining(null_b, NX_RES_RAM) != 0 { return 47 }
127
128 return 0
129}