nx_log_jsonl_test.nx source
↩ module page · 177 lines · 7429 B
1// nx_log_jsonl_test.nx -- smoke for structured JSONL log emitter.
2//
3// expect_exit: 0
4//
5// license_tier: ORIGINAL
6
7import "nx_syscalls_x86_64.nx"
8import "nx_log_jsonl.nx"
9
10func bytes_eq(a: *u8, b: *u8, n: i64) -> i64 {
11 var i: i64 = 0
12 while i < n {
13 if a[i] != b[i] { return 0 }
14 i = i + 1
15 }
16 return 1
17}
18
19func bytes_contains(haystack: *u8, h_n: i64, needle: *u8, n_n: i64) -> i64 {
20 if n_n > h_n { return 0 }
21 var i: i64 = 0
22 while i <= h_n - n_n {
23 if bytes_eq(((haystack as i64) + i) as *u8, needle, n_n) == 1 { return 1 }
24 i = i + 1
25 }
26 return 0
27}
28
29func main() -> i64 {
30 // ---- Level + verdict enum gates ----
31 if nxl_level_is_valid(NXL_DEBUG) != 1 { return 1 }
32 if nxl_level_is_valid(NXL_ERROR) != 1 { return 2 }
33 if nxl_level_is_valid(NXL_LEVEL_N) != 0 { return 3 }
34 if nxl_verdict_is_valid(NXL_OK) != 1 { return 4 }
35 if nxl_verdict_is_valid(NXL_VERDICT_N) != 0 { return 5 }
36
37 if bytes_eq(nxl_level_name(NXL_DEBUG), "DEBUG" as *u8, 5) != 1 { return 6 }
38 if bytes_eq(nxl_level_name(NXL_INFO), "INFO" as *u8, 4) != 1 { return 7 }
39 if bytes_eq(nxl_level_name(NXL_WARN), "WARN" as *u8, 4) != 1 { return 8 }
40 if bytes_eq(nxl_level_name(NXL_ERROR), "ERROR" as *u8, 5) != 1 { return 9 }
41 if nxl_level_name_len(NXL_INFO) != 4 { return 10 }
42 if nxl_level_name_len(NXL_DEBUG) != 5 { return 11 }
43
44 // ---- Simple INFO line ----
45 let buf: *u8 = sys_mmap(1024)
46 let off: *i64 = sys_mmap(8) as *i64
47 let scratch: *u8 = sys_mmap(64)
48 off[0] = 0
49 let rc1: i64 = nx_log_emit_line(buf, off, 1024,
50 1234,
51 NXL_INFO,
52 "nx_audit" as *u8, 8,
53 "daemon started" as *u8, 14,
54 scratch)
55 if rc1 != NXL_OK { return 20 }
56 // Expected:
57 // {"ts_ms":1234,"level":"INFO","module":"nx_audit","msg":"daemon started"}\n
58 let exp1: *u8 = "{\"ts_ms\":1234,\"level\":\"INFO\",\"module\":\"nx_audit\",\"msg\":\"daemon started\"}\n" as *u8
59 if off[0] != 73 { return 21 }
60 if bytes_eq(buf, exp1, 73) != 1 { return 22 }
61
62 // ---- WARN line with int field ----
63 off[0] = 0
64 let rc2: i64 = nx_log_emit_line_with_int(buf, off, 1024,
65 5000,
66 NXL_WARN,
67 "nx_super" as *u8, 8,
68 "crash detected" as *u8, 14,
69 "n_restarts" as *u8, 10,
70 3,
71 scratch)
72 if rc2 != NXL_OK { return 30 }
73 if bytes_contains(buf, off[0],
74 "\"level\":\"WARN\"" as *u8, 14) != 1 { return 31 }
75 if bytes_contains(buf, off[0],
76 "\"n_restarts\":3" as *u8, 14) != 1 { return 32 }
77 if bytes_contains(buf, off[0],
78 "\"ts_ms\":5000" as *u8, 12) != 1 { return 33 }
79
80 // ---- ERROR line with string field ----
81 off[0] = 0
82 let rc3: i64 = nx_log_emit_line_with_str(buf, off, 1024,
83 9999,
84 NXL_ERROR,
85 "nx_dns" as *u8, 6,
86 "bind failed" as *u8, 11,
87 "err" as *u8, 3,
88 "EADDRINUSE" as *u8, 10,
89 scratch)
90 if rc3 != NXL_OK { return 40 }
91 if bytes_contains(buf, off[0],
92 "\"level\":\"ERROR\"" as *u8, 15) != 1 { return 41 }
93 if bytes_contains(buf, off[0],
94 "\"err\":\"EADDRINUSE\"" as *u8, 18) != 1 { return 42 }
95
96 // ---- JSON escape: quotes + backslash in msg ----
97 off[0] = 0
98 let evil: *u8 = "user said \"hi\\there\"" as *u8
99 let rc4: i64 = nx_log_emit_line(buf, off, 1024,
100 1, NXL_INFO,
101 "x" as *u8, 1,
102 evil, 20,
103 scratch)
104 if rc4 != NXL_OK { return 50 }
105 // Quotes must be escaped to \"
106 if bytes_contains(buf, off[0],
107 "user said \\\"hi" as *u8, 14) != 1 { return 51 }
108 // Backslash must be escaped to \\
109 if bytes_contains(buf, off[0],
110 "\\\\there" as *u8, 7) != 1 { return 52 }
111
112 // ---- JSON escape: control char (newline in user input) ----
113 off[0] = 0
114 let injection: *u8 = sys_mmap(32)
115 injection[0] = 0x68 as u8 // h
116 injection[1] = 0x65 as u8 // e
117 injection[2] = 0x6c as u8 // l
118 injection[3] = 0x6c as u8 // l
119 injection[4] = 0x6f as u8 // o
120 injection[5] = 0x0a as u8 // \n (injection attempt)
121 injection[6] = 0x65 as u8 // e
122 injection[7] = 0x76 as u8 // v
123 injection[8] = 0x69 as u8 // i
124 injection[9] = 0x6c as u8 // l
125 let rc5: i64 = nx_log_emit_line(buf, off, 1024,
126 1, NXL_WARN,
127 "x" as *u8, 1,
128 injection, 10,
129 scratch)
130 if rc5 != NXL_OK { return 60 }
131 // The newline INSIDE the message must be encoded as \n, not
132 // actual newline. Verify by counting actual newlines in output
133 // -- should be exactly ONE (the terminating \n after }).
134 var nl_count: i64 = 0
135 var i: i64 = 0
136 while i < off[0] {
137 if buf[i] == 0x0a as u8 { nl_count = nl_count + 1 }
138 i = i + 1
139 }
140 if nl_count != 1 { return 61 }
141 // Verify the escaped form is in the body.
142 if bytes_contains(buf, off[0], "hello\\nevil" as *u8, 11) != 1 { return 62 }
143
144 // ---- BAD_LEVEL ----
145 off[0] = 0
146 if nx_log_emit_line(buf, off, 1024, 1, 99,
147 "x" as *u8, 1, "y" as *u8, 1,
148 scratch) != NXL_BAD_LEVEL { return 70 }
149
150 // ---- BAD_ARG paths ----
151 off[0] = 0
152 if nx_log_emit_line(0 as *u8, off, 1024, 1, NXL_INFO,
153 "x" as *u8, 1, "y" as *u8, 1,
154 scratch) != NXL_BAD_ARG { return 80 }
155 if nx_log_emit_line(buf, 0 as *i64, 1024, 1, NXL_INFO,
156 "x" as *u8, 1, "y" as *u8, 1,
157 scratch) != NXL_BAD_ARG { return 81 }
158 if nx_log_emit_line(buf, off, 1024, 1, NXL_INFO,
159 0 as *u8, 1, "y" as *u8, 1,
160 scratch) != NXL_BAD_ARG { return 82 }
161 if nx_log_emit_line(buf, off, 1024, 1, NXL_INFO,
162 "x" as *u8, 0, "y" as *u8, 1,
163 scratch) != NXL_BAD_ARG { return 83 }
164 if nx_log_emit_line(buf, off, 1024, 1, NXL_INFO,
165 "x" as *u8, 1, 0 as *u8, 1,
166 scratch) != NXL_BAD_ARG { return 84 }
167
168 // ---- OOM_BUFFER on too-small buffer ----
169 let tiny: *u8 = sys_mmap(16)
170 let t_off: *i64 = sys_mmap(8) as *i64
171 t_off[0] = 0
172 if nx_log_emit_line(tiny, t_off, 16, 1, NXL_INFO,
173 "x" as *u8, 1, "abcdefg" as *u8, 7,
174 scratch) != NXL_OOM_BUFFER { return 90 }
175
176 return 0
177}