fed-prims: Phase J — http-request + 6 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 2m48s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 2m48s
NATIVE-ONLY http-request primitive (bin/sx_server.ml). HTTP/1.1 over Unix sockets + gethostbyname; inline http:// URL parsing (full url-parse deferred to Phase K); Connection: close + Host + Content-Length headers auto-supplied; reads response via Content-Length or read-to-EOF; chunked transfer-encoding rejected. Test bin/test_http_client.sh spins a Phase-H echo server and drives a second sx_server: GET+query, POST+body, 404, custom request header reflected, non-http scheme rejected, integer status — 6/6. WASM boot green (prim not in lib); Erlang conformance 530/530.
This commit is contained in:
80
hosts/ocaml/bin/test_http_client.sh
Executable file
80
hosts/ocaml/bin/test_http_client.sh
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase J test — native-only http-request client primitive.
|
||||
# Reuses Phase H's http-listen to spin up an echo server, then drives
|
||||
# a separate sx_server via the epoch protocol to issue http-request
|
||||
# calls and assert response shape + headers + body.
|
||||
set -u
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
SRV=_build/default/bin/sx_server.exe
|
||||
PORT=${HTTP_CLIENT_TEST_PORT:-8921}
|
||||
PASS=0
|
||||
FAIL=0
|
||||
ok() { echo " PASS: $1"; PASS=$((PASS+1)); }
|
||||
bad() { echo " FAIL: $1 — $2"; FAIL=$((FAIL+1)); }
|
||||
|
||||
if [ ! -x "$SRV" ]; then
|
||||
echo "build sx_server.exe first (dune build bin/sx_server.exe)"; exit 1
|
||||
fi
|
||||
|
||||
# /echo echoes method/path/query/body and reflects request X-Custom
|
||||
# back as response X-Got; /missing-test → 404.
|
||||
H='(begin (define (h req) (if (= (get req "path") "/echo") {:status 200 :headers {"X-Echo" (get req "method") "X-Got" (get (get req "headers") "x-custom")} :body (str "M=" (get req "method") " P=" (get req "path") " Q=" (get req "query") " B=" (get req "body"))} (if (= (get req "path") "/missing-test") {:status 404 :body "nope"} {:status 500 :body "err"}))) (http-listen '"$PORT"' h))'
|
||||
ESC=${H//\"/\\\"}
|
||||
|
||||
{ printf '(epoch 1)\n(eval "%s")\n' "$ESC"; sleep 60; } | "$SRV" >/tmp/test_http_client_srv.out 2>&1 &
|
||||
SVPID=$!
|
||||
trap 'kill $SVPID 2>/dev/null; wait 2>/dev/null' EXIT
|
||||
|
||||
up=0
|
||||
for _ in $(seq 1 50); do
|
||||
curl -s -o /dev/null "http://127.0.0.1:$PORT/echo" 2>/dev/null && { up=1; break; }
|
||||
sleep 0.2
|
||||
done
|
||||
[ "$up" = 1 ] || { echo " FAIL: server did not start"; cat /tmp/test_http_client_srv.out; exit 1; }
|
||||
|
||||
emit() {
|
||||
# $1 = epoch num, $2 = raw SX form. Wraps in (eval "...") with quotes escaped.
|
||||
local esc=${2//\"/\\\"}
|
||||
printf '(epoch %s)\n(eval "%s")\n' "$1" "$esc"
|
||||
}
|
||||
|
||||
DRV_OUT=/tmp/test_http_client_drv.out
|
||||
{
|
||||
emit 1 '(let ((r (http-request "GET" "http://127.0.0.1:'"$PORT"'/echo?x=1" {} ""))) (str "S=" (get r "status") " E=" (get (get r "headers") "x-echo") " B=" (get r "body")))'
|
||||
emit 2 '(let ((r (http-request "POST" "http://127.0.0.1:'"$PORT"'/echo" {} "hello"))) (str "S=" (get r "status") " B=" (get r "body")))'
|
||||
emit 3 '(let ((r (http-request "GET" "http://127.0.0.1:'"$PORT"'/missing-test" {} ""))) (str "S=" (get r "status") " B=" (get r "body")))'
|
||||
emit 4 '(let ((r (http-request "GET" "http://127.0.0.1:'"$PORT"'/echo" {"X-Custom" "myval"} ""))) (get (get r "headers") "x-got"))'
|
||||
emit 5 '(http-request "GET" "ftp://nope" {} "")'
|
||||
emit 6 '(let ((r (http-request "GET" "http://127.0.0.1:'"$PORT"'/echo" {} ""))) (get r "status"))'
|
||||
} | "$SRV" >"$DRV_OUT" 2>&1
|
||||
|
||||
# eval results come back as (ok-len N L)\n<body>\n — grep the body content.
|
||||
grep -q '^"S=200 E=GET B=M=GET P=/echo Q=x=1 B="$' "$DRV_OUT" \
|
||||
&& ok "GET status + echo header + body" \
|
||||
|| bad "GET" "$(grep -A1 '^(ok-len 1 ' "$DRV_OUT" | tail -1)"
|
||||
|
||||
grep -q '^"S=200 B=M=POST P=/echo Q= B=hello"$' "$DRV_OUT" \
|
||||
&& ok "POST body roundtrip" \
|
||||
|| bad "POST" "$(grep -A1 '^(ok-len 2 ' "$DRV_OUT" | tail -1)"
|
||||
|
||||
grep -q '^"S=404 B=nope"$' "$DRV_OUT" \
|
||||
&& ok "404 status + body" \
|
||||
|| bad "404" "$(grep -A1 '^(ok-len 3 ' "$DRV_OUT" | tail -1)"
|
||||
|
||||
grep -q '^"myval"$' "$DRV_OUT" \
|
||||
&& ok "custom request header reaches server" \
|
||||
|| bad "custom-header" "$(grep -A1 '^(ok-len 4 ' "$DRV_OUT" | tail -1)"
|
||||
|
||||
R5=$(grep '^(error 5 ' "$DRV_OUT" | head -1)
|
||||
echo "$R5" | grep -q 'URL must start with http' \
|
||||
&& ok "non-http scheme rejected" \
|
||||
|| bad "bad-url" "$R5"
|
||||
|
||||
# Status is an Integer (200), serialized bare without quotes.
|
||||
grep -q '^200$' "$DRV_OUT" \
|
||||
&& ok "response status is integer 200" \
|
||||
|| bad "status-integer" "$(grep -A1 '^(ok-len 6 ' "$DRV_OUT" | tail -1)"
|
||||
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
[ "$FAIL" = 0 ]
|
||||
Reference in New Issue
Block a user