nx_moonraker_io_test.nx source
↩ module page · 109 lines · 3731 B
1// nx_moonraker_io_test.nx -- REAL network roundtrip test.
2//
3// Parent: acts as a fake Moonraker server -- listens on a loopback
4// port, accepts the connection, reads the POST request, validates
5// it contains expected markers, sends back a canned HTTP/1.1 200 OK
6// response.
7//
8// Child: builds + sends the Moonraker POST /printer/print/start
9// request via nx_mr_post_loopback (composes nx_mr_build_post_request
10// + tcp_connect_loopback + sys_write + sys_read). Verifies the
11// response status is 200. Exits with assertion code.
12//
13// Bytes flow over a real loopback socket through the real Linux
14// kernel TCP stack inside qemu -- this is REAL network I/O, not a
15// mock.
16//
17// expect_exit: 0
18// license_tier: ORIGINAL
19
20import "nx_syscalls.nx"
21import "nx_tls13_io.nx"
22import "nx_moonraker_client.nx"
23import "nx_moonraker_io.nx"
24
25const TEST_PORT: i64 = 18447
26
27// Verify buf contains needle as a contiguous substring.
28func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 {
29 var nlen: i64 = 0
30 while needle[nlen] != 0 { nlen = nlen + 1 }
31 if len < nlen { return 0 }
32 var i: i64 = 0
33 while i <= len - nlen {
34 var j: i64 = 0
35 var matched: i64 = 1
36 while j < nlen {
37 if buf[i + j] != needle[j] { matched = 0; j = nlen }
38 j = j + 1
39 }
40 if matched == 1 { return 1 }
41 i = i + 1
42 }
43 return 0
44}
45
46func main() -> i64 {
47 let listen_fd: i64 = tcp_listen_loopback(TEST_PORT)
48 if listen_fd < 0 { return 1 }
49
50 let pid: i64 = sys_fork()
51 if pid < 0 { return 2 }
52
53 if pid == 0 {
54 // ===== Child: client =====
55 // Brief spin so parent has time to call accept.
56 var spin: i64 = 0
57 while spin < 50000 { spin = spin + 1 }
58
59 let scratch: *u8 = sys_mmap(4096)
60 let resp: *u8 = sys_mmap(4096)
61 let host: *u8 = "127.0.0.1:18447"
62 let path: *u8 = "/printer/print/start"
63 let body: *u8 = "{\"filename\":\"cube.gcode\"}"
64 let api_key: *u8 = "demo"
65
66 let n_resp: i64 = nx_mr_post_loopback(TEST_PORT,
67 host, 15,
68 path, 20,
69 body, 26,
70 api_key, 4,
71 scratch, 4096,
72 resp, 4096)
73 if n_resp <= 0 { sys_exit(10) }
74
75 // Parse HTTP status code from response.
76 let status: i64 = nx_mr_parse_status(resp, n_resp)
77 if status != 200 { sys_exit(11) }
78
79 // Verify response contains expected substring.
80 if smoke_contains(resp, n_resp, "HTTP/1.1 200 OK") != 1 { sys_exit(12) }
81
82 sys_exit(0)
83 }
84
85 // ===== Parent: fake Moonraker =====
86 let cfd: i64 = sys_accept(listen_fd)
87 if cfd < 0 { return 3 }
88
89 let req_buf: *u8 = sys_mmap(4096)
90 let n_req: i64 = sys_read(cfd, req_buf, 4096)
91 if n_req <= 0 { return 4 }
92
93 // Validate the request looks like what we built.
94 if smoke_contains(req_buf, n_req, "POST /printer/print/start") != 1 { return 5 }
95 if smoke_contains(req_buf, n_req, "Host: 127.0.0.1:18447") != 1 { return 6 }
96 if smoke_contains(req_buf, n_req, "X-Api-Key: demo") != 1 { return 7 }
97 if smoke_contains(req_buf, n_req, "{\"filename\":\"cube.gcode\"}") != 1 { return 8 }
98
99 // Canned 200 OK response.
100 let resp: *u8 = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
101 var rl: i64 = 0
102 while resp[rl] != 0 { rl = rl + 1 }
103 let n_w: i64 = sys_write(cfd, resp, rl)
104 if n_w != rl { return 9 }
105
106 sys_close(cfd)
107 sys_close(listen_fd)
108 return 0
109}