#!/usr/bin/env nu # Real service acceptance tests. Every created box is removed, including failures. def check [condition: bool, message: string] { if not $condition { error make {msg: $message} } print $'ok - ($message)' } def call [component: path, root: path, args: list] { ^wasmtime run -S http -S cli-exit-with-code=y --dir $'($root)::/' $component ...$args | complete } def require [] { let result = $in if $result.exit_code != 0 { error make {msg: $'box failed: ($result.stderr)'} } $result } def main [component: path = '/home/surma/src/gitea.surma.technology/surma/sausage/target/p1-tools/wasm32-wasip2/release/box.wasm'] { let component = ($component | path expand) let root = (^mktemp -d /tmp/box-test-XXXXXXXX | str trim) mkdir ($root | path join project sub) '{"scripts":{"test":"node sub/test.js"}}' | save ($root | path join project package.json) 'const fs = require("node:fs"); require("node:assert/strict").equal(2 + 2, 4); fs.writeFileSync("result.txt", "npm test passed\n");' | save ($root | path join project sub test.js) 'binary-safe file payload' | save ($root | path join input.txt) let created = (call $component $root [create --ttl 600]) let id = if $created.stdout =~ 'tc-[a-z0-9]{6}' { $created.stdout | str trim } else { $created.stderr | parse --regex '(?Ptc-[a-z0-9]{6})' | get id | first | default '' } if $id == '' { error make {msg: $'create returned no recoverable id: ($created.stderr); test files: ($root)'} } let outcome = try { $created | require | ignore check ($id =~ '^tc-[a-z0-9]{6}$') 'create returns id' let inventory = (call $component $root [ls] | require) check ($inventory.stdout | str contains $id) 'ls contains box' let exec = (call $component $root [exec $id -- sh -c 'printf hello; printf problem >&2; exit 7']) check ($exec.exit_code == 7 and $exec.stdout == 'hello' and ($exec.stderr | str contains 'problem')) 'exec preserves both streams and exit 7' call $component $root [put $id /input.txt /tmp/file.txt] | require | ignore call $component $root [get $id /tmp/file.txt /returned.txt] | require | ignore check ((open --raw ($root | path join returned.txt)) == (open --raw ($root | path join input.txt))) 'file put/get round trip' call $component $root [put $id /project /work] | require | ignore call $component $root [get $id /work /tree] | require | ignore check ((open --raw ($root | path join tree sub test.js)) == (open --raw ($root | path join project sub test.js))) 'tree round trip retains subfolder' let npm = (call $component $root [exec $id --timeout 120 -- sh -c 'cd /work && npm test'] | require) check ($npm.stdout | str contains 'node sub/test.js') 'npm test runs in box' call $component $root [get $id /work/result.txt /result.txt] | require | ignore check ((open --raw ($root | path join result.txt)) == "npm test passed\n") 'Node result returns to world' let large = (call $component $root [exec $id -- node -e 'process.stdout.write(Buffer.alloc(1200003,255)); process.stderr.write("raw stderr");'] | require) check (($large.stdout | str length --utf-8-bytes) < 16600) 'large binary inline output stays bounded' let archive = ($large.stderr | parse --regex 'box stdout archive: (?P[^\n]+)' | get path | first) let bytes = (open --raw ($root | path join ($archive | str trim --left --char '/'))) check (($bytes | bytes length) == 1200003) 'full binary archive retains byte total' let repeated = (call $component $root [exec $id -- sh -c 'printf collision-check'] | require) check ($repeated.stdout == 'collision-check') 'later exec returns output' check ((open --raw ($root | path join ($archive | str trim --left --char '/'))) == $bytes) 'later archive leaves earlier output intact' let log = (call $component $root [logs $id] | require) check ($log.stderr | str contains 'box build archive:') 'logs retains build archive' let wit = (^wasm-tools component wit $component | complete) check ($wit.exit_code == 0) 'component WIT inspection' print $wit.stdout let imports = ($wit.stdout | lines | where {|line| $line | str trim | str starts-with 'import ' }) check ($imports | all {|line| $line | str trim | str starts-with 'import wasi:' }) 'component imports only WASI interfaces' null } catch {|failure| $failure } let removed = (call $component $root [rm $id]) print $removed.stderr check ($removed.exit_code == 0) $'rm removes ($id)' let after = (call $component $root [ls] | require) check (not ($after.stdout | str contains $id)) 'removed box absent from ls' if $outcome != null { error make {msg: $'acceptance failed: ($outcome); retained evidence: ($root)'} } print $'PASS; world files and archives: ($root)' }