code wiki / (root) / nx_moonraker_client_test.nx

nx_moonraker_client_test.nx source

↩ module page · 132 lines · 5135 B

1// nx_moonraker_client_test.nx -- verify URL building + JSON body + 2// HTTP request assembly + status parsing against known-byte expected 3// outputs. 4// 5// Closed-form invariants (every byte hand-verified): 6// (a) Filename validation: "test.gcode" safe; quotes/backslash refused. 7// (b) URL build: base "http://10.0.0.5:7125" + path "/printer/info" 8// -> "http://10.0.0.5:7125/printer/info" (33 bytes). 9// (c) JSON print-start body for "voron.gcode" -> 10// 11// (28 bytes including the {} and quotes). 12// (d) POST request bytes start with "POST /printer/print/start HTTP/1.1\r\n" 13// 14// contain "Host: 10.0.0.5:7125\r\n", 15// 16// contain "Content-Type: application/json\r\n", 17// 18// contain "Content-Length: 28\r\n\r\n", and end with the JSON body. 19// (e) GET request bytes start with "GET /printer/info HTTP/1.1\r\n". 20// (f) GET request with API key contains "X-Api-Key: secret\r\n". 21// (g) Status-line parser: "HTTP/1.1 200 OK\r\n" -> 200. 22// (h) Status-line parser: "HTTP/1.1 503 Service" -> 503. 23// (i) Status-line parser malformed: "HTTPx/1.1 200 OK" -> -1. 24// 25// expect_exit: 0 26// license_tier: ORIGINAL 27 28import "nx_syscalls.nx" 29import "nx_moonraker_client.nx" 30 31func smoke_buf_eq(buf: *u8, expected: *u8, n: i64) -> i64 { 32 var i: i64 = 0 33 while i < n { 34 if (buf[i] as i64) != (expected[i] as i64) { return 0 } 35 i = i + 1 36 } 37 return 1 38} 39 40func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 { 41 var nlen: i64 = 0 42 while needle[nlen] != 0 { nlen = nlen + 1 } 43 if len < nlen { return 0 } 44 var i: i64 = 0 45 while i <= len - nlen { 46 var j: i64 = 0 47 var matched: i64 = 1 48 while j < nlen { 49 if buf[i + j] != needle[j] { matched = 0; j = nlen } 50 j = j + 1 51 } 52 if matched == 1 { return 1 } 53 i = i + 1 54 } 55 return 0 56} 57 58func cstr_len(s: *u8) -> i64 { 59 var i: i64 = 0 60 while s[i] != 0 { i = i + 1 } 61 return i 62} 63 64func main() -> i64 { 65 let buf: *u8 = sys_mmap(4096) 66 67 // --- (a) Filename validation --- 68 let safe_fn: *u8 = "test.gcode" 69 if nx_mr_filename_is_safe(safe_fn, 10) != 1 { return 10 } 70 let quote_fn: *u8 = "bad\"name.gcode" 71 if nx_mr_filename_is_safe(quote_fn, 14) != 0 { return 11 } 72 let back_fn: *u8 = "bad\\name" 73 if nx_mr_filename_is_safe(back_fn, 8) != 0 { return 12 } 74 75 // --- (b) URL build --- 76 let base: *u8 = "http://10.0.0.5:7125" 77 let path: *u8 = "/printer/info" 78 let n_url: i64 = nx_mr_build_url(base, 20, path, 13, buf, 4096) 79 if n_url != 33 { return 20 } 80 if smoke_buf_eq(buf, "http://10.0.0.5:7125/printer/info", 33) != 1 { return 21 } 81 82 // --- (c) JSON print-start body --- 83 let fn: *u8 = "voron.gcode" 84 let n_json: i64 = nx_mr_build_print_start_body(fn, 11, buf, 4096) 85 // {"filename":"voron.gcode"} -> 13 + 11 + 2 = 26 bytes (no, let me count) 86 // { 1 87 // "filename" 10 88 // : 1 89 // "voron.gcode" 13 90 // } 1 91 // = 26 bytes 92 if n_json != 26 { return 30 } 93 if smoke_buf_eq(buf, "{\"filename\":\"voron.gcode\"}", 26) != 1 { return 31 } 94 95 // --- (d) POST request --- 96 let host: *u8 = "10.0.0.5:7125" 97 let start_path: *u8 = "/printer/print/start" 98 let body: *u8 = "{\"filename\":\"voron.gcode\"}" 99 let n_post: i64 = nx_mr_build_post_request(host, 13, 100 start_path, 20, 101 body, 26, 102 0 as *u8, 0, 103 buf, 4096) 104 if n_post <= 0 { return 40 } 105 if smoke_contains(buf, n_post, "POST /printer/print/start HTTP/1.1\r\n") != 1 { return 41 } 106 if smoke_contains(buf, n_post, "Host: 10.0.0.5:7125\r\n") != 1 { return 42 } 107 if smoke_contains(buf, n_post, "Content-Type: application/json\r\n") != 1 { return 43 } 108 if smoke_contains(buf, n_post, "Content-Length: 26\r\n") != 1 { return 44 } 109 // Body included after \r\n\r\n 110 if smoke_contains(buf, n_post, "{\"filename\":\"voron.gcode\"}") != 1 { return 45 } 111 112 // --- (e) GET request --- 113 let n_get: i64 = nx_mr_build_get_request(host, 13, path, 13, 114 0 as *u8, 0, buf, 4096) 115 if n_get <= 0 { return 50 } 116 if smoke_contains(buf, n_get, "GET /printer/info HTTP/1.1\r\n") != 1 { return 51 } 117 if smoke_contains(buf, n_get, "Host: 10.0.0.5:7125\r\n") != 1 { return 52 } 118 119 // --- (f) GET with API key --- 120 let api_key: *u8 = "secret" 121 let n_get_auth: i64 = nx_mr_build_get_request(host, 13, path, 13, 122 api_key, 6, buf, 4096) 123 if n_get_auth <= 0 { return 60 } 124 if smoke_contains(buf, n_get_auth, "X-Api-Key: secret\r\n") != 1 { return 61 } 125 126 // --- (g)(h)(i) Status parser --- 127 if nx_mr_parse_status("HTTP/1.1 200 OK\r\n", 17) != 200 { return 70 } 128 if nx_mr_parse_status("HTTP/1.1 503 Service", 20) != 503 { return 71 } 129 if nx_mr_parse_status("HTTPx/1.1 200 OK\r\n", 18) != -1 { return 72 } 130 131 return 0 132}