code wiki / (root) / prop_nxtask_store_test.nx

prop_nxtask_store_test.nx source

↩ module page · 113 lines · 3730 B

1// prop_nxtask_store_test.nx -- property test for nxtask serializer. 2// 3// Property: for any sequence of nxtask operations (add, claim, 4// close, add_dep), serialize -> deserialize round-trip preserves 5// every observable field. If this ever fails, a persisted agent 6// state would silently corrupt on reload. 7// 8// Runs 500 iterations. Each builds a random graph (3-8 tasks, 9// random mutations), serializes, deserializes, compares. 10 11import "syscalls.nx" 12import "nxtask.nx" 13import "nxtask_store.nx" 14import "prop_test.nx" 15 16func compare_tasks(a: *Task, b: *Task) -> i64 { 17 if a.state != b.state { return 0 } 18 if a.desc_len != b.desc_len { return 0 } 19 if a.claimed_by_len != b.claimed_by_len { return 0 } 20 if a.summary_len != b.summary_len { return 0 } 21 if a.n_blocked != b.n_blocked { return 0 } 22 if a.created_ns != b.created_ns { return 0 } 23 if a.updated_ns != b.updated_ns { return 0 } 24 // Compare desc bytes. 25 var i: i64 = 0 26 while i < a.desc_len { 27 if a.desc[i] != b.desc[i] { return 0 } 28 i = i + 1 29 } 30 return 1 31} 32 33func main() -> i64 { 34 let g: *PropGen = prop_gen_new(0xBEEF0042) 35 let buf: *u8 = sys_mmap(32768) 36 37 var iter: i64 = 0 38 while iter < 500 { 39 g.iter = iter 40 41 let n_tasks: i64 = prop_gen_range(g, 1, 8) 42 let graph: *TaskGraph = nxtask_graph_new(n_tasks + 8) 43 44 // Add n_tasks with random (but deterministic) descriptions. 45 var t: i64 = 0 46 while t < n_tasks { 47 let desc: *u8 = sys_mmap(32) 48 let dlen: i64 = prop_gen_range(g, 5, 25) 49 var di: i64 = 0 50 while di < dlen { 51 desc[di] = prop_gen_printable(g) 52 di = di + 1 53 } 54 desc[dlen] = 0 55 nxtask_add(graph, desc, dlen, iter * 100 + t) 56 t = t + 1 57 } 58 59 // Random mutations: claim some, close some, add some deps. 60 t = 0 61 while t < n_tasks { 62 let r: i64 = prop_gen_range(g, 0, 3) 63 if r == 0 { 64 nxtask_claim(graph, t, "agent" as *u8, 5, iter * 200 + t) 65 } 66 if r == 1 { 67 nxtask_claim(graph, t, "agent" as *u8, 5, iter * 200 + t) 68 nxtask_close(graph, t, "done" as *u8, 4, iter * 300 + t) 69 } 70 if r == 2 { 71 if t > 0 { 72 let blocker: i64 = prop_gen_range(g, 0, t - 1) 73 nxtask_add_dep(graph, t, blocker) 74 } 75 } 76 // r == 3: leave it open 77 t = t + 1 78 } 79 80 // Serialize + deserialize. 81 let n: i64 = nxtask_serialize(graph, buf, 32768) 82 if n < 0 { 83 prop_report(g, "serialize overflow" as *u8) 84 return __syscall(93, 10, 0, 0, 0, 0, 0) 85 } 86 87 let graph2: *TaskGraph = nxtask_deserialize(buf, n) 88 if graph2 == (0 as *TaskGraph) { 89 prop_report(g, "deserialize null" as *u8) 90 return __syscall(93, 11, 0, 0, 0, 0, 0) 91 } 92 if graph2.n_tasks != graph.n_tasks { 93 prop_report(g, "n_tasks mismatch" as *u8) 94 return __syscall(93, 12, 0, 0, 0, 0, 0) 95 } 96 97 // Per-task field equality. 98 var k: i64 = 0 99 while k < graph.n_tasks { 100 let ta: *Task = task_at(graph, k) 101 let tb: *Task = task_at(graph2, k) 102 if compare_tasks(ta, tb) == 0 { 103 prop_report(g, "task field mismatch" as *u8) 104 return __syscall(93, 13, 0, 0, 0, 0, 0) 105 } 106 k = k + 1 107 } 108 109 iter = iter + 1 110 } 111 112 return 0 113}