- cf session new / turn / close / list / get
- --json flag mirrors v0.1 convention
- close is idempotent (exit 0 on already-closed)
- Bearer hygiene preserved (regression guard test)
- tests/test_session.sh: ~18 tests, 44 assertions
- README "Sessions (v0.2)" section
v0.1 subcommands unchanged.
Spec: memory/spec-clawdforge-v0.2.md
Server core: 940861f
476 lines
16 KiB
Bash
Executable file
476 lines
16 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# test_session.sh — smoke tests for v0.2 session subcommands in clients/bash/cf
|
|
#
|
|
# Strategy: same fake-curl pattern as test_cf.sh but the fake reads the
|
|
# requested URL/method from the captured argv and emits a canned per-endpoint
|
|
# response body. The body for each endpoint is configurable via env vars so
|
|
# individual tests can drive 200/4xx/5xx and already_closed shapes without
|
|
# rewriting the fake.
|
|
#
|
|
# Run:
|
|
# bash clients/bash/test/test_session.sh
|
|
#
|
|
# Exit 0 on all-pass, 1 on first failure.
|
|
|
|
set -euo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
CF="$HERE/../cf"
|
|
[[ -x "$CF" ]] || { echo "fatal: cf not found or not exec at $CF" >&2; exit 1; }
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
mkdir -p "$WORK/bin" "$WORK/cfgdir"
|
|
REQ_LOG="$WORK/req.log"
|
|
|
|
# Fake curl tuned for /sessions endpoints. Behavior per request:
|
|
# * Records argv (and any --config / --data-binary contents) to REQ_LOG.
|
|
# * Inspects the URL and METHOD pulled from argv to pick a response body.
|
|
# * Body source can be overridden per-endpoint via env vars:
|
|
# CF_TEST_SESSIONS_NEW_BODY — POST /sessions
|
|
# CF_TEST_SESSIONS_NEW_STATUS — default 200
|
|
# CF_TEST_SESSIONS_TURN_BODY — POST /sessions/.../turn
|
|
# CF_TEST_SESSIONS_TURN_STATUS — default 200
|
|
# CF_TEST_SESSIONS_GET_BODY — GET /sessions/<id>
|
|
# CF_TEST_SESSIONS_GET_STATUS — default 200
|
|
# CF_TEST_SESSIONS_LIST_BODY — GET /sessions
|
|
# CF_TEST_SESSIONS_LIST_STATUS — default 200
|
|
# CF_TEST_SESSIONS_CLOSE_BODY — DELETE /sessions/<id>
|
|
# CF_TEST_SESSIONS_CLOSE_STATUS — default 200
|
|
# * Defaults are sensible canned bodies that pass minimal jq checks.
|
|
cat > "$WORK/bin/curl" <<'FAKE_CURL'
|
|
#!/usr/bin/env bash
|
|
log="${CF_TEST_REQ_LOG:?must export CF_TEST_REQ_LOG}"
|
|
{
|
|
echo "__ARGV_COUNT__=$#"
|
|
for a in "$@"; do
|
|
printf '__ARGV__=%s\n' "$a"
|
|
done
|
|
prev=""
|
|
for a in "$@"; do
|
|
if [[ "$prev" == "--config" ]]; then
|
|
echo "__CONFIG_FILE__=$a"
|
|
if [[ -f "$a" ]]; then
|
|
echo "__CONFIG_CONTENTS__"
|
|
cat "$a"
|
|
echo "__END_CONFIG__"
|
|
fi
|
|
fi
|
|
if [[ "$prev" == "--data-binary" && "$a" == @* ]]; then
|
|
df="${a#@}"
|
|
echo "__DATAFILE__=$df"
|
|
if [[ -f "$df" ]]; then
|
|
echo "__DATAFILE_CONTENTS__"
|
|
cat "$df"
|
|
echo "__END_DATAFILE__"
|
|
fi
|
|
fi
|
|
if [[ "$prev" == "--data-binary" && "$a" != @* ]]; then
|
|
echo "__DATA_INLINE__"
|
|
printf '%s' "$a"
|
|
echo
|
|
echo "__END_DATA_INLINE__"
|
|
fi
|
|
prev="$a"
|
|
done
|
|
} > "$log"
|
|
|
|
# Pull METHOD and URL out of argv. The cf script uses:
|
|
# curl -sS -X METHOD URL ...
|
|
# so we can scan for -X.
|
|
method="GET"
|
|
url=""
|
|
prev=""
|
|
for a in "$@"; do
|
|
if [[ "$prev" == "-X" ]]; then method="$a"; fi
|
|
if [[ "$a" == http* && -z "$url" ]]; then url="$a"; fi
|
|
prev="$a"
|
|
done
|
|
|
|
# Pick a body + status per endpoint shape. We branch on (method, path).
|
|
# Default 200; override via env.
|
|
body=""
|
|
status=200
|
|
|
|
# Trim querystring for path matching.
|
|
path="${url#http*://*/}"
|
|
path="/${path%%\?*}"
|
|
|
|
# Build default bodies as separate vars so the env-override parameter
|
|
# expansions don't have to embed JSON braces (which collide with bash
|
|
# brace substitution).
|
|
default_new='{"ok":true,"session_id":"sess-aaa-111","agent":"claude","created_at":1714000000,"cwd":"/tmp/sess"}'
|
|
default_turn='{"ok":true,"session_id":"sess-aaa-111","turn_index":1,"events":[{"type":"text","content":"hello world"}],"stop_reason":"end_turn","duration_ms":42}'
|
|
default_list='{"ok":true,"sessions":[{"session_id":"sess-aaa-111","agent":"claude","turn_count":2,"created_at":1714000000,"closed_at":null},{"session_id":"sess-bbb-222","agent":"claude","turn_count":0,"created_at":1714000050,"closed_at":1714000099}],"count":2}'
|
|
default_get='{"ok":true,"session_id":"sess-aaa-111","agent":"claude","cwd":"/tmp/sess","created_at":1714000000,"last_turn_at":1714000050,"turn_count":1,"closed_at":1714000099,"live":false,"meta":null}'
|
|
default_close='{"ok":true}'
|
|
|
|
case "$method:$path" in
|
|
POST:/sessions)
|
|
body="${CF_TEST_SESSIONS_NEW_BODY:-$default_new}"
|
|
status="${CF_TEST_SESSIONS_NEW_STATUS:-200}"
|
|
;;
|
|
POST:/sessions/*/turn)
|
|
body="${CF_TEST_SESSIONS_TURN_BODY:-$default_turn}"
|
|
status="${CF_TEST_SESSIONS_TURN_STATUS:-200}"
|
|
;;
|
|
GET:/sessions)
|
|
body="${CF_TEST_SESSIONS_LIST_BODY:-$default_list}"
|
|
status="${CF_TEST_SESSIONS_LIST_STATUS:-200}"
|
|
;;
|
|
GET:/sessions/*)
|
|
body="${CF_TEST_SESSIONS_GET_BODY:-$default_get}"
|
|
status="${CF_TEST_SESSIONS_GET_STATUS:-200}"
|
|
;;
|
|
DELETE:/sessions/*)
|
|
body="${CF_TEST_SESSIONS_CLOSE_BODY:-$default_close}"
|
|
status="${CF_TEST_SESSIONS_CLOSE_STATUS:-200}"
|
|
;;
|
|
GET:/healthz)
|
|
body='{"ok":true,"claude_present":true,"acpx_present":true}'
|
|
;;
|
|
POST:/run)
|
|
body='{"ok":true,"result":"v0.1-pass-through"}'
|
|
;;
|
|
*)
|
|
body='{"ok":true}'
|
|
;;
|
|
esac
|
|
|
|
# Print body then the cf-status marker that _request parses.
|
|
printf '%s\n__cf_status__=%s' "$body" "$status"
|
|
exit 0
|
|
FAKE_CURL
|
|
chmod +x "$WORK/bin/curl"
|
|
|
|
# Baseline cf.env (chmod 600).
|
|
CF_ENV="$WORK/cfgdir/clawdforge/cf.env"
|
|
mkdir -p "$(dirname "$CF_ENV")"
|
|
cat > "$CF_ENV" <<EOF
|
|
CLAWDFORGE_URL=http://test.invalid:8800
|
|
CLAWDFORGE_TOKEN=tok-secret-xyz
|
|
CLAWDFORGE_ADMIN_TOKEN=admin-tok-abc
|
|
EOF
|
|
chmod 600 "$CF_ENV"
|
|
|
|
run_cf() {
|
|
XDG_CONFIG_HOME="$WORK/cfgdir" \
|
|
CF_TEST_REQ_LOG="$REQ_LOG" \
|
|
PATH="$WORK/bin:$PATH" \
|
|
"$CF" "$@"
|
|
}
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
fail() { echo "FAIL: $*" >&2; FAIL=$((FAIL+1)); }
|
|
pass() { echo "PASS: $*"; PASS=$((PASS+1)); }
|
|
|
|
assert_eq() {
|
|
local got="$1" want="$2" name="$3"
|
|
if [[ "$got" == "$want" ]]; then pass "$name"
|
|
else
|
|
fail "$name — want=[$want] got=[$got]"
|
|
fi
|
|
}
|
|
|
|
assert_contains() {
|
|
local needle="$1" hay="$2" name="$3"
|
|
if [[ "$hay" == *"$needle"* ]]; then pass "$name"
|
|
else
|
|
fail "$name — expected: $needle"
|
|
echo "--- haystack ---" >&2
|
|
printf '%s\n' "$hay" >&2
|
|
echo "--- end ---" >&2
|
|
fi
|
|
}
|
|
|
|
assert_not_contains() {
|
|
local needle="$1" hay="$2" name="$3"
|
|
if [[ "$hay" != *"$needle"* ]]; then pass "$name"
|
|
else
|
|
fail "$name — found unexpectedly: $needle"
|
|
echo "--- haystack ---" >&2
|
|
printf '%s\n' "$hay" >&2
|
|
echo "--- end ---" >&2
|
|
fi
|
|
}
|
|
|
|
# Pull a JSON object body out of REQ_LOG (between __DATA_INLINE__ markers).
|
|
read_body() {
|
|
local body="" in_block=0 line
|
|
while IFS= read -r line; do
|
|
if [[ "$line" == "__DATA_INLINE__" ]]; then in_block=1; continue; fi
|
|
if [[ "$line" == "__END_DATA_INLINE__" ]]; then in_block=0; continue; fi
|
|
if (( in_block )); then body+="$line"$'\n'; fi
|
|
done < "$REQ_LOG"
|
|
body="${body%$'\n'}"
|
|
printf '%s' "$body"
|
|
}
|
|
|
|
# ---- Test 1: cf session new prints just the UUID -------------------------
|
|
echo "# Test 1: session new prints UUID only"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session new)"
|
|
assert_eq "$out" "sess-aaa-111" "T1.session-new-uuid-only"
|
|
# Sanity: the URL we hit was POST /sessions
|
|
url_argv="$(grep '^__ARGV__=http' "$REQ_LOG" | head -n1 || true)"
|
|
assert_contains "/sessions" "$url_argv" "T1.session-new-url"
|
|
|
|
# ---- Test 2: cf session new --json prints full JSON ----------------------
|
|
echo "# Test 2: session new --json full body"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session new --json)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
ok="$(jq -r '.ok' <<<"$out" 2>/dev/null || echo error)"
|
|
assert_eq "$ok" "true" "T2.session-new-json-ok"
|
|
sid="$(jq -r '.session_id' <<<"$out" 2>/dev/null || echo error)"
|
|
assert_eq "$sid" "sess-aaa-111" "T2.session-new-json-sid"
|
|
else
|
|
assert_contains "session_id" "$out" "T2.session-new-json-fallback"
|
|
fi
|
|
|
|
# ---- Test 3: cf session new --agent / --meta hit body -------------------
|
|
echo "# Test 3: session new --agent + --meta in body"
|
|
: > "$REQ_LOG"
|
|
run_cf session new --agent claude --meta '{"label":"unit-test","n":3}' >/dev/null
|
|
body="$(read_body)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
agent_val="$(jq -r '.agent' <<<"$body" 2>/dev/null || echo error)"
|
|
assert_eq "$agent_val" "claude" "T3.body-agent"
|
|
meta_label="$(jq -r '.meta.label' <<<"$body" 2>/dev/null || echo error)"
|
|
assert_eq "$meta_label" "unit-test" "T3.body-meta-label"
|
|
meta_n="$(jq -r '.meta.n' <<<"$body" 2>/dev/null || echo error)"
|
|
assert_eq "$meta_n" "3" "T3.body-meta-n"
|
|
fi
|
|
|
|
# ---- Test 4: --meta rejects non-object literal --------------------------
|
|
echo "# Test 4: --meta non-object rejected"
|
|
set +e
|
|
out="$(run_cf session new --meta '"just-a-string"' 2>&1)"; rc=$?
|
|
set -e
|
|
if (( rc != 0 )) && [[ "$out" == *"--meta must be a JSON object"* ]]; then
|
|
pass "T4.meta-rejects-non-object"
|
|
else
|
|
fail "T4.meta-rejects-non-object — rc=$rc out=$out"
|
|
fi
|
|
|
|
# ---- Test 5: cf session turn writes text to stdout -----------------------
|
|
echo "# Test 5: session turn default = text events"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session turn sess-aaa-111 'hi there')"
|
|
assert_eq "$out" "hello world" "T5.turn-prints-text"
|
|
|
|
# Body sanity
|
|
body="$(read_body)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
prompt_val="$(jq -r '.prompt' <<<"$body" 2>/dev/null || echo error)"
|
|
assert_eq "$prompt_val" "hi there" "T5.turn-body-prompt"
|
|
fi
|
|
|
|
# ---- Test 6: cf session turn --json writes full JSON ---------------------
|
|
echo "# Test 6: session turn --json full JSON"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session turn sess-aaa-111 'hi' --json)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
ti="$(jq -r '.turn_index' <<<"$out" 2>/dev/null || echo err)"
|
|
assert_eq "$ti" "1" "T6.turn-json-turn-index"
|
|
evcount="$(jq -r '.events | length' <<<"$out" 2>/dev/null || echo err)"
|
|
assert_eq "$evcount" "1" "T6.turn-json-events-count"
|
|
fi
|
|
|
|
# ---- Test 7: cf session turn --files goes through escape pipeline -------
|
|
echo "# Test 7: session turn --files JSON injection guard"
|
|
: > "$REQ_LOG"
|
|
# Quote-escape attempt without a comma
|
|
run_cf session turn sess-aaa-111 'go' --files 'tok_a"]:"smug":"y' >/dev/null
|
|
body="$(read_body)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
has_smug="$(jq -r 'has("smug")' <<<"$body" 2>/dev/null || echo err)"
|
|
assert_eq "$has_smug" "false" "T7.turn-no-injection"
|
|
files_first="$(jq -r '.files[0]' <<<"$body" 2>/dev/null || echo err)"
|
|
assert_eq "$files_first" 'tok_a"]:"smug":"y' "T7.turn-files-roundtrip"
|
|
fi
|
|
|
|
# ---- Test 8: cf session turn --trace writes JSON to file ----------------
|
|
echo "# Test 8: session turn --trace writes JSON to file"
|
|
TRACE="$WORK/trace.json"
|
|
: > "$REQ_LOG"
|
|
run_cf session turn sess-aaa-111 'go' --trace "$TRACE" >/dev/null
|
|
if [[ -s "$TRACE" ]]; then
|
|
if command -v jq >/dev/null 2>&1; then
|
|
sid="$(jq -r '.session_id' <"$TRACE" 2>/dev/null || echo err)"
|
|
assert_eq "$sid" "sess-aaa-111" "T8.trace-file-contents"
|
|
else
|
|
assert_contains "sess-aaa-111" "$(cat "$TRACE")" "T8.trace-file-contents"
|
|
fi
|
|
else
|
|
fail "T8.trace-file-contents — trace file empty/missing"
|
|
fi
|
|
|
|
# ---- Test 9: cf session close → "closed" first time ---------------------
|
|
echo "# Test 9: session close idempotency"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session close sess-aaa-111)"
|
|
assert_eq "$out" "closed" "T9.close-first-time"
|
|
# Second call → already-closed (server returns already_closed:true)
|
|
: > "$REQ_LOG"
|
|
out="$(CF_TEST_SESSIONS_CLOSE_BODY='{"ok":true,"already_closed":true}' \
|
|
run_cf session close sess-aaa-111)"
|
|
assert_eq "$out" "already-closed" "T9.close-second-time"
|
|
|
|
# Both calls exited 0 (we'd have failed earlier under set -e).
|
|
pass "T9.close-both-exit-0"
|
|
|
|
# ---- Test 10: cf session list prints expected count ---------------------
|
|
echo "# Test 10: session list table"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session list)"
|
|
# Header + 2 rows = 3 lines
|
|
line_count="$(printf '%s' "$out" | grep -c .)"
|
|
assert_eq "$line_count" "3" "T10.list-3-lines"
|
|
assert_contains "sess-aaa-111" "$out" "T10.list-row-1"
|
|
assert_contains "sess-bbb-222" "$out" "T10.list-row-2"
|
|
|
|
# --json variant
|
|
: > "$REQ_LOG"
|
|
out_json="$(run_cf session list --json)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
count="$(jq -r '.count' <<<"$out_json" 2>/dev/null || echo err)"
|
|
assert_eq "$count" "2" "T10.list-json-count"
|
|
fi
|
|
|
|
# ---- Test 11: cf session get returns state with closed_at ---------------
|
|
echo "# Test 11: session get state shape"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf session get sess-aaa-111)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
closed="$(jq -r '.closed_at' <<<"$out" 2>/dev/null || echo err)"
|
|
assert_eq "$closed" "1714000099" "T11.get-closed-at"
|
|
sid="$(jq -r '.session_id' <<<"$out" 2>/dev/null || echo err)"
|
|
assert_eq "$sid" "sess-aaa-111" "T11.get-session-id"
|
|
fi
|
|
|
|
# ---- Test 12: 404 (cross-token) bubbles up as exit 4 + non-bearer msg ---
|
|
echo "# Test 12: cross-token 404 handling"
|
|
: > "$REQ_LOG"
|
|
set +e
|
|
out="$(CF_TEST_SESSIONS_GET_STATUS=404 \
|
|
CF_TEST_SESSIONS_GET_BODY='{"detail":"session not found"}' \
|
|
run_cf session get sess-aaa-111 2>&1)"
|
|
rc=$?
|
|
set -e
|
|
if (( rc == 4 )); then
|
|
pass "T12.404-exit-4"
|
|
else
|
|
fail "T12.404-exit-4 — rc=$rc out=$out"
|
|
fi
|
|
assert_contains "session not found" "$out" "T12.404-error-message"
|
|
# Hard regression guard: bearer NEVER appears in error stream.
|
|
assert_not_contains "tok-secret-xyz" "$out" "T12.404-no-bearer-leak"
|
|
|
|
# ---- Test 13: 500 turn failure bubbles up as exit 5 + no bearer ---------
|
|
echo "# Test 13: 500 turn failure"
|
|
: > "$REQ_LOG"
|
|
set +e
|
|
out="$(CF_TEST_SESSIONS_TURN_STATUS=500 \
|
|
CF_TEST_SESSIONS_TURN_BODY='{"detail":"acpx pool full"}' \
|
|
run_cf session turn sess-aaa-111 hi 2>&1)"
|
|
rc=$?
|
|
set -e
|
|
if (( rc == 5 )); then
|
|
pass "T13.500-exit-5"
|
|
else
|
|
fail "T13.500-exit-5 — rc=$rc out=$out"
|
|
fi
|
|
assert_contains "acpx pool full" "$out" "T13.500-error-message"
|
|
assert_not_contains "tok-secret-xyz" "$out" "T13.500-no-bearer-leak"
|
|
|
|
# ---- Test 14: bearer not in argv on /sessions calls (S1 regression) -----
|
|
echo "# Test 14: bearer hygiene on /sessions/* (S1 regression guard)"
|
|
: > "$REQ_LOG"
|
|
run_cf session new >/dev/null
|
|
argv_only="$(grep '^__ARGV__=' "$REQ_LOG" || true)"
|
|
assert_not_contains "tok-secret-xyz" "$argv_only" "T14.new-no-bearer-in-argv"
|
|
# But it MUST be in the --config file contents.
|
|
assert_contains "Bearer tok-secret-xyz" "$(cat "$REQ_LOG")" "T14.new-bearer-in-config"
|
|
|
|
: > "$REQ_LOG"
|
|
run_cf session turn sess-aaa-111 hi >/dev/null
|
|
argv_only="$(grep '^__ARGV__=' "$REQ_LOG" || true)"
|
|
assert_not_contains "tok-secret-xyz" "$argv_only" "T14.turn-no-bearer-in-argv"
|
|
|
|
: > "$REQ_LOG"
|
|
run_cf session close sess-aaa-111 >/dev/null
|
|
argv_only="$(grep '^__ARGV__=' "$REQ_LOG" || true)"
|
|
assert_not_contains "tok-secret-xyz" "$argv_only" "T14.close-no-bearer-in-argv"
|
|
|
|
: > "$REQ_LOG"
|
|
run_cf session list >/dev/null
|
|
argv_only="$(grep '^__ARGV__=' "$REQ_LOG" || true)"
|
|
assert_not_contains "tok-secret-xyz" "$argv_only" "T14.list-no-bearer-in-argv"
|
|
|
|
: > "$REQ_LOG"
|
|
run_cf session get sess-aaa-111 >/dev/null
|
|
argv_only="$(grep '^__ARGV__=' "$REQ_LOG" || true)"
|
|
assert_not_contains "tok-secret-xyz" "$argv_only" "T14.get-no-bearer-in-argv"
|
|
|
|
# ---- Test 15: invalid session id rejected before HTTP call --------------
|
|
echo "# Test 15: invalid session id (path traversal)"
|
|
: > "$REQ_LOG"
|
|
set +e
|
|
out="$(run_cf session get '../../etc/passwd' 2>&1)"; rc=$?
|
|
set -e
|
|
if (( rc == 2 )) && [[ "$out" == *"invalid session id"* ]]; then
|
|
pass "T15.bad-id-rejected"
|
|
else
|
|
fail "T15.bad-id-rejected — rc=$rc out=$out"
|
|
fi
|
|
# And no curl call was made (REQ_LOG should be empty).
|
|
if [[ ! -s "$REQ_LOG" ]]; then
|
|
pass "T15.bad-id-no-network"
|
|
else
|
|
fail "T15.bad-id-no-network — REQ_LOG non-empty"
|
|
fi
|
|
|
|
# ---- Test 16: session turn - reads stdin --------------------------------
|
|
echo "# Test 16: session turn - reads stdin"
|
|
: > "$REQ_LOG"
|
|
out="$(echo 'piped-prompt-here' | run_cf session turn sess-aaa-111 -)"
|
|
assert_eq "$out" "hello world" "T16.turn-stdin-stdout"
|
|
body="$(read_body)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
prompt_val="$(jq -r '.prompt' <<<"$body" 2>/dev/null || echo err)"
|
|
# cat preserves the trailing newline only if present in input
|
|
assert_contains "piped-prompt-here" "$prompt_val" "T16.turn-stdin-body"
|
|
fi
|
|
|
|
# ---- Test 17: v0.1 cf run regression — unchanged path ------------------
|
|
echo "# Test 17: v0.1 cf run still works (regression)"
|
|
: > "$REQ_LOG"
|
|
out="$(run_cf run 'hi' --model sonnet)"
|
|
if command -v jq >/dev/null 2>&1; then
|
|
result="$(jq -r '.result' <<<"$out" 2>/dev/null || echo err)"
|
|
assert_eq "$result" "v0.1-pass-through" "T17.run-pass-through"
|
|
fi
|
|
url_argv="$(grep '^__ARGV__=http' "$REQ_LOG" | head -n1 || true)"
|
|
assert_contains "/run" "$url_argv" "T17.run-hits-/run"
|
|
assert_not_contains "/sessions" "$url_argv" "T17.run-doesnt-hit-/sessions"
|
|
|
|
# ---- Test 18: unknown session subcommand -------------------------------
|
|
echo "# Test 18: unknown session subcommand"
|
|
set +e
|
|
out="$(run_cf session bogus 2>&1)"; rc=$?
|
|
set -e
|
|
if (( rc == 2 )) && [[ "$out" == *"unknown session subcommand"* ]]; then
|
|
pass "T18.unknown-subcmd"
|
|
else
|
|
fail "T18.unknown-subcmd — rc=$rc out=$out"
|
|
fi
|
|
|
|
echo ""
|
|
echo "============================="
|
|
echo "PASS: $PASS FAIL: $FAIL"
|
|
echo "============================="
|
|
if (( FAIL > 0 )); then exit 1; fi
|
|
exit 0
|