#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" TMP_DIR=$(mktemp -d) EDGE_PID="" NODE_PID="" EDGE_FD_OPEN=0 cleanup() { if [ "$EDGE_FD_OPEN" -eq 1 ]; then { echo "/exit" >&3; } 2>/dev/null || true exec 3>&- 2>/dev/null || true fi if [ -n "$EDGE_PID" ]; then wait "$EDGE_PID" 2>/dev/null || true; fi if [ -n "$NODE_PID" ]; then kill "$NODE_PID" 2>/dev/null || true; fi rm -rf "$TMP_DIR" 2>/dev/null || true } trap cleanup EXIT PORT=$((31000 + RANDOM % 5000)) BOOTSTRAP_PORT=$((21000 + RANDOM % 5000)) OPENAI_PORT=$((36000 + RANDOM % 5000)) EDGE_METRICS_PORT=$((46000 + RANDOM % 5000)) NODE_METRICS_PORT=$((51000 + RANDOM % 5000)) MODEL="cli-smoke-model" wait_port() { local host="$1" local port="$2" local label="$3" local deadline=$((SECONDS + 20)) while ! timeout 1 bash -c 'cat < /dev/null > /dev/tcp/"$1"/"$2"' _ "$host" "$port" 2>/dev/null; do if (( SECONDS >= deadline )); then echo "[openai-cli-workspace] $label did not open on $host:$port" return 1 fi sleep 0.2 done } EDGE_CONFIG="$TMP_DIR/edge.yaml" NODE_CONFIG="$TMP_DIR/node.yaml" WORKSPACE="$TMP_DIR/real_workspace" mkdir -p "$WORKSPACE" git -C "$WORKSPACE" init git -C "$WORKSPACE" config user.name "test" git -C "$WORKSPACE" config user.email "test@example.com" cat > "$EDGE_CONFIG" < "$NODE_CONFIG" < "$EDGE_OUT" 2>&1 & EDGE_PID=$! exec 3> "$TMP_DIR/edge_fifo" EDGE_FD_OPEN=1 wait_port 127.0.0.1 "$PORT" "edge node transport" wait_port 127.0.0.1 "$OPENAI_PORT" "edge openai api" IOP_NODE_CONFIG="$NODE_CONFIG" "$REPO_ROOT/scripts/dev/node.sh" > "$NODE_OUT" 2>&1 & NODE_PID=$! deadline=$((SECONDS + 30)) while ! grep -q '\[node0-evt\] connected reason="registered"' "$EDGE_OUT"; do if (( SECONDS >= deadline )); then echo "[openai-cli-workspace] node registration timed out" echo "=== EDGE OUTPUT ==="; cat "$EDGE_OUT" echo "=== NODE OUTPUT ==="; cat "$NODE_OUT" exit 1 fi sleep 0.2 done RESPONSES_OUT="$TMP_DIR/responses.json" curl -fsS \ -H "Content-Type: application/json" \ -d '{"model":"'"$MODEL"'","input":"echo '\''marker_content'\'' > marker.txt && echo '\''IOP_CLI_SMOKE_OK'\''","stream":false,"metadata":{"request_id":"e2e-openai-cli-workspace","task_id":"task-smoke","workspace":"'"$WORKSPACE"'"}}' \ "http://127.0.0.1:$OPENAI_PORT/v1/responses" > "$RESPONSES_OUT" grep -q "IOP_CLI_SMOKE_OK" "$RESPONSES_OUT" grep -q '"output_text"' "$RESPONSES_OUT" # 1. marker file이 workspace 안에 생성되었는지 검증 if [ ! -f "$WORKSPACE/marker.txt" ]; then echo "[cli-workspace] marker file not found in workspace" exit 1 fi if [ "$(cat "$WORKSPACE/marker.txt" | xargs)" != "marker_content" ]; then echo "[cli-workspace] marker content mismatch" exit 1 fi # 2. repo root와 temp parent에는 marker가 없어야 한다 if [ -f "$REPO_ROOT/marker.txt" ]; then echo "[cli-workspace] marker file leaked to repo root" exit 1 fi if [ -f "$TMP_DIR/marker.txt" ]; then echo "[cli-workspace] marker file leaked to temp parent" exit 1 fi # 3. git -C "$WORKSPACE" status --short로 변경 확인 GIT_STATUS=$(git -C "$WORKSPACE" status --short) if [[ "$GIT_STATUS" != *"marker.txt"* ]]; then echo "[cli-workspace] git status does not show marker.txt" echo "Actual git status: $GIT_STATUS" exit 1 fi # 4. iop-edge smoke openai 검증 (expect-file, expect-contains 사용) SMOKE_OUT="$TMP_DIR/iop-edge-smoke-openai.txt" (cd "$REPO_ROOT" && go run ./apps/edge/cmd/edge smoke openai \ --model "$MODEL" \ --base-url "http://127.0.0.1:$OPENAI_PORT" \ --prompt "echo 'marker_smoke' > marker_smoke.txt && echo 'IOP_CLI_SMOKE_OK'" \ --workspace "$WORKSPACE" \ --expect-file "marker_smoke.txt" \ --expect-contains "marker_smoke" \ --timeout 20s) > "$SMOKE_OUT" grep -q "Step 3: Checking /v1/responses ... \[OK\]" "$SMOKE_OUT" grep -q "IOP Edge OpenAI Smoke Test SUCCESS!" "$SMOKE_OUT" if grep -i -E "node reported error|error run_id=|\[[^]]+-evt\] error|panic:" "$EDGE_OUT" "$NODE_OUT" >/dev/null; then echo "[openai-cli-workspace] detected failure marker in logs" echo "=== EDGE OUTPUT ==="; cat "$EDGE_OUT" echo "=== NODE OUTPUT ==="; cat "$NODE_OUT" exit 1 fi echo "[openai-cli-workspace] OpenAI-compatible CLI workspace authoring test PASSED."