cp_cli lives in agent-runtimes; previously every planner call ran 'python3 -m lib.cp_cli' from the current repo with no --context, so the script only worked inside agent-runtimes. The context now resolves from ~/.cpconfig by matching project_id to the repo directory name. Verified live from hatchmate (item + parent + documents fetched via the hatchmate context). Claude-Session: https://claude.ai/code/session_01JgJbWzVJioVznVTFyQFEfx
269 lines
9.6 KiB
Bash
Executable File
269 lines
9.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test-bg-model-call.sh — Verify bg-model-call dryrun behaviour against the spec.
|
|
#
|
|
# Strategy: all assertions use --dryrun (-n), so no CP calls are made and
|
|
# no output files are written. Prompt files are created in a tempdir.
|
|
|
|
set -uo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
BG_MODEL_CALL="$REPO_ROOT/scripts/bg-model-call"
|
|
|
|
GREEN='\033[0;32m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m'
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
assert_contains() {
|
|
local label=$1 needle=$2 haystack=$3
|
|
if [[ "$haystack" == *"$needle"* ]]; then
|
|
printf " ${GREEN}PASS${NC} %s\n" "$label"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
printf " ${RED}FAIL${NC} %s\n" "$label"
|
|
printf " expected to contain: %s\n" "$needle"
|
|
printf " actual output:\n"
|
|
printf '%s\n' "$haystack" | sed 's/^/ /'
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
assert_not_contains() {
|
|
local label=$1 needle=$2 haystack=$3
|
|
if [[ "$haystack" != *"$needle"* ]]; then
|
|
printf " ${GREEN}PASS${NC} %s\n" "$label"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
printf " ${RED}FAIL${NC} %s\n" "$label"
|
|
printf " expected NOT to contain: %s\n" "$needle"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
assert_exit_code() {
|
|
local label=$1 expected=$2 actual=$3
|
|
if [[ "$expected" == "$actual" ]]; then
|
|
printf " ${GREEN}PASS${NC} %s (exit=%s)\n" "$label" "$actual"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
printf " ${RED}FAIL${NC} %s (expected exit=%s, got exit=%s)\n" "$label" "$expected" "$actual"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
# Create a temp directory for prompt and output files
|
|
TMPDIR_TEST="$(mktemp -d)"
|
|
trap 'rm -rf "$TMPDIR_TEST"' EXIT
|
|
|
|
PROMPT_FILE="${TMPDIR_TEST}/prompt.txt"
|
|
OUTPUT_FILE="${TMPDIR_TEST}/result.txt"
|
|
echo "This is a test prompt for the spec review." > "$PROMPT_FILE"
|
|
|
|
run() {
|
|
"$BG_MODEL_CALL" "$@" 2>&1
|
|
}
|
|
|
|
# === Pre-flight ===
|
|
if [[ ! -x "$BG_MODEL_CALL" ]]; then
|
|
echo "bg-model-call not found or not executable at $BG_MODEL_CALL" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# === Test 1: --help ===
|
|
echo "Test 1: --help"
|
|
out=$(run --help)
|
|
rc=$?
|
|
assert_exit_code "--help exits 0" 0 "$rc"
|
|
assert_contains "--help shows script name" "bg-model-call" "$out"
|
|
assert_contains "--help shows --model" "--model" "$out"
|
|
assert_contains "--help shows --prompt" "--prompt" "$out"
|
|
assert_contains "--help shows --output" "--output" "$out"
|
|
assert_contains "--help shows --dryrun" "--dryrun" "$out"
|
|
assert_contains "--help shows --template" "--template" "$out"
|
|
|
|
# === Test 2: basic minimax dryrun ===
|
|
echo
|
|
echo "Test 2: minimax dryrun"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "minimax dryrun exits 0" 0 "$rc"
|
|
assert_contains "shows dryrun header" "[dryrun]" "$out"
|
|
assert_contains "shows model" "minimax" "$out"
|
|
assert_contains "shows resolved template" "minimax-planning" "$out"
|
|
assert_contains "shows CP URL default" "http://localhost:8100" "$out"
|
|
assert_contains "shows project ID default" "bg-model-call" "$out"
|
|
assert_contains "shows task name" "bg-model-call-minimax" "$out"
|
|
assert_contains "shows prompt file path" "$PROMPT_FILE" "$out"
|
|
assert_contains "shows output file path" "$OUTPUT_FILE" "$out"
|
|
assert_contains "shows sentinel path" "${OUTPUT_FILE}.done" "$out"
|
|
assert_contains "shows prompt size" "bytes" "$out"
|
|
assert_not_contains "no CP calls in dryrun" "Submitting task" "$out"
|
|
|
|
# === Test 3: sonnet dryrun — template mapping ===
|
|
echo
|
|
echo "Test 3: sonnet dryrun — template mapping"
|
|
out=$(run --dryrun --model sonnet --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "sonnet dryrun exits 0" 0 "$rc"
|
|
assert_contains "sonnet maps to sonnet-code-repo" "sonnet-code-repo" "$out"
|
|
assert_contains "sonnet task name correct" "bg-model-call-sonnet" "$out"
|
|
|
|
# === Test 4: haiku dryrun — template mapping ===
|
|
echo
|
|
echo "Test 4: haiku dryrun — template mapping"
|
|
out=$(run --dryrun --model haiku --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "haiku dryrun exits 0" 0 "$rc"
|
|
assert_contains "haiku maps to haiku-code-repo" "haiku-code-repo" "$out"
|
|
|
|
# === Test 5: opus dryrun — template mapping ===
|
|
echo
|
|
echo "Test 5: opus dryrun — template mapping"
|
|
out=$(run --dryrun --model opus --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "opus dryrun exits 0" 0 "$rc"
|
|
assert_contains "opus maps to opus-code-repo" "opus-code-repo" "$out"
|
|
|
|
# === Test 6: --template override ===
|
|
echo
|
|
echo "Test 6: --template override"
|
|
out=$(run --dryrun --template minimax-planning --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "--template override exits 0" 0 "$rc"
|
|
assert_contains "template override shown" "minimax-planning" "$out"
|
|
# No model line since only --template was given, not --model
|
|
assert_not_contains "no model line when using --template only" "Model:" "$out"
|
|
|
|
# === Test 7: custom --project and --task-name ===
|
|
echo
|
|
echo "Test 7: custom project and task name"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE" \
|
|
--project my-project --task-name review-task)
|
|
rc=$?
|
|
assert_exit_code "custom project/task exits 0" 0 "$rc"
|
|
assert_contains "custom project shown" "my-project" "$out"
|
|
assert_contains "custom task name shown" "review-task" "$out"
|
|
|
|
# === Test 8: custom --url ===
|
|
echo
|
|
echo "Test 8: custom --url"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE" \
|
|
--url "http://10.111.1.11:31800")
|
|
rc=$?
|
|
assert_exit_code "custom url exits 0" 0 "$rc"
|
|
assert_contains "custom URL shown" "http://10.111.1.11:31800" "$out"
|
|
|
|
# === Test 9: CP_URL env var ===
|
|
echo
|
|
echo "Test 9: CP_URL env var"
|
|
out=$(CP_URL="http://my-cp:9000" run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "CP_URL env var exits 0" 0 "$rc"
|
|
assert_contains "CP_URL env var used" "http://my-cp:9000" "$out"
|
|
|
|
# === Test 10: -n shorthand ===
|
|
echo
|
|
echo "Test 10: -n shorthand for dryrun"
|
|
out=$(run -n --model sonnet --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "-n shorthand exits 0" 0 "$rc"
|
|
assert_contains "-n shows dryrun header" "[dryrun]" "$out"
|
|
|
|
# === Test 11: error — missing --model and --template ===
|
|
echo
|
|
echo "Test 11: error — missing --model and --template"
|
|
out=$(run --dryrun --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "missing model exits 1" 1 "$rc"
|
|
assert_contains "missing model error message" "--model is required" "$out"
|
|
|
|
# === Test 12: error — missing --prompt ===
|
|
echo
|
|
echo "Test 12: error — missing --prompt"
|
|
out=$(run --dryrun --model minimax --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "missing prompt exits 1" 1 "$rc"
|
|
assert_contains "missing prompt error" "--prompt is required" "$out"
|
|
|
|
# === Test 13: error — missing --output ===
|
|
echo
|
|
echo "Test 13: error — missing --output"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE")
|
|
rc=$?
|
|
assert_exit_code "missing output exits 1" 1 "$rc"
|
|
assert_contains "missing output error" "--output is required" "$out"
|
|
|
|
# === Test 14: error — unknown model alias ===
|
|
echo
|
|
echo "Test 14: error — unknown model alias"
|
|
out=$(run --dryrun --model bogusmodel --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "unknown model exits 1" 1 "$rc"
|
|
assert_contains "unknown model error" "Unknown model alias" "$out"
|
|
assert_contains "unknown model error lists valid values" "minimax" "$out"
|
|
|
|
# === Test 15: error — prompt file not found ===
|
|
echo
|
|
echo "Test 15: error — prompt file not found"
|
|
out=$(run --dryrun --model minimax --prompt "/tmp/definitely-does-not-exist-99999.txt" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "missing prompt file exits 1" 1 "$rc"
|
|
assert_contains "missing prompt file error" "Cannot read prompt file" "$out"
|
|
|
|
# === Test 16: error — output directory does not exist ===
|
|
echo
|
|
echo "Test 16: error — output directory does not exist"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "/nonexistent/dir/result.txt")
|
|
rc=$?
|
|
assert_exit_code "missing output dir exits 1" 1 "$rc"
|
|
assert_contains "missing output dir error" "Output directory does not exist" "$out"
|
|
|
|
# === Test 17: error — invalid timeout ===
|
|
echo
|
|
echo "Test 17: error — invalid --timeout"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE" --timeout abc)
|
|
rc=$?
|
|
assert_exit_code "invalid timeout exits 1" 1 "$rc"
|
|
assert_contains "invalid timeout error" "--timeout must be a positive integer" "$out"
|
|
|
|
# === Test 18: error — invalid poll-interval ===
|
|
echo
|
|
echo "Test 18: error — invalid --poll-interval"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE" --poll-interval 0)
|
|
rc=$?
|
|
assert_exit_code "invalid poll-interval exits 1" 1 "$rc"
|
|
assert_contains "invalid poll-interval error" "--poll-interval must be a positive integer" "$out"
|
|
|
|
# === Test 19: custom timeout and poll-interval shown in dryrun ===
|
|
echo
|
|
echo "Test 19: custom timeout and poll-interval in dryrun"
|
|
out=$(run --dryrun --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE" \
|
|
--timeout 3600 --poll-interval 30)
|
|
rc=$?
|
|
assert_exit_code "custom timeout/poll exits 0" 0 "$rc"
|
|
assert_contains "custom timeout shown" "3600s" "$out"
|
|
assert_contains "custom poll shown" "30s" "$out"
|
|
|
|
# === Test 20: unknown flag ===
|
|
echo
|
|
echo "Test 20: unknown flag"
|
|
out=$(run --dryrun --bogus-flag --model minimax --prompt "$PROMPT_FILE" --output "$OUTPUT_FILE")
|
|
rc=$?
|
|
assert_exit_code "unknown flag exits 1" 1 "$rc"
|
|
assert_contains "unknown flag error" "Unknown flag" "$out"
|
|
|
|
# === Summary ===
|
|
echo
|
|
echo "================================"
|
|
TOTAL=$((PASS + FAIL))
|
|
if [[ "$FAIL" -eq 0 ]]; then
|
|
printf "${GREEN}All %d tests passed${NC}\n" "$TOTAL"
|
|
exit 0
|
|
else
|
|
printf "${RED}%d of %d tests failed${NC}\n" "$FAIL" "$TOTAL"
|
|
exit 1
|
|
fi
|