Stream Gate 준비 실패에서도 요청 terminal 관측 계약을 지키고, direct provider identity 마이그레이션 누락으로 기존 검증과 운영 설정이 깨지지 않게 한다.
190 lines
5.5 KiB
Bash
Executable file
190 lines
5.5 KiB
Bash
Executable file
#!/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" <<EOF
|
|
server:
|
|
listen: "127.0.0.1:$PORT"
|
|
metrics:
|
|
port: $EDGE_METRICS_PORT
|
|
bootstrap:
|
|
listen: "127.0.0.1:$BOOTSTRAP_PORT"
|
|
artifact_dir: "$TMP_DIR/artifacts"
|
|
openai:
|
|
enabled: true
|
|
listen: "127.0.0.1:$OPENAI_PORT"
|
|
provider_id: "cli-smoke-provider"
|
|
adapter: "cli"
|
|
session_id: "openai"
|
|
timeout_sec: 30
|
|
strict_output: false
|
|
model_routes:
|
|
- model: "$MODEL"
|
|
adapter: "cli"
|
|
target: "smoke-sh"
|
|
workspace_required: true
|
|
console:
|
|
adapter: cli
|
|
target: smoke-sh
|
|
session_id: default
|
|
nodes:
|
|
- id: test-node
|
|
alias: test-node
|
|
token: test-token
|
|
adapters:
|
|
cli:
|
|
enabled: true
|
|
profiles:
|
|
smoke-sh:
|
|
command: "sh"
|
|
args:
|
|
- "-c"
|
|
persistent: false
|
|
terminal: false
|
|
mode: "oneshot"
|
|
EOF
|
|
|
|
cat > "$NODE_CONFIG" <<EOF
|
|
transport:
|
|
edge_addr: "127.0.0.1:$PORT"
|
|
token: test-token
|
|
reconnect_interval: 1s
|
|
metrics:
|
|
port: $NODE_METRICS_PORT
|
|
node:
|
|
id: test-node
|
|
alias: test-node
|
|
EOF
|
|
|
|
EDGE_OUT="$TMP_DIR/edge.out"
|
|
NODE_OUT="$TMP_DIR/node.out"
|
|
mkfifo "$TMP_DIR/edge_fifo"
|
|
IOP_EDGE_CONFIG="$EDGE_CONFIG" "$REPO_ROOT/scripts/dev/edge.sh" < "$TMP_DIR/edge_fifo" > "$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."
|