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}