Executable
+285
@@ -0,0 +1,285 @@
|
||||
#!/bin/bash
|
||||
# test-tmux-send-prompt-integ.sh — tmux-send-prompt.sh 真实集成测试(可观察模式)
|
||||
#
|
||||
# 用法: bash scripts/test-tmux-send-prompt-integ.sh
|
||||
#
|
||||
# 布局:
|
||||
# ┌──────────────────┬──────────────────┐
|
||||
# │ cc pane (左) │ ctrl pane (右) │
|
||||
# │ 接收命令并回复 │ 运行测试、显示 │
|
||||
# └──────────────────┴──────────────────┘
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ─── 配置 ───
|
||||
SESSION="test-send"
|
||||
SCRIPT="/workspace/scripts/tmux-send-prompt.sh"
|
||||
TEST_DIR=$(mktemp -d)
|
||||
|
||||
# ─── 辅助函数 ───
|
||||
|
||||
wait_for_prompt() {
|
||||
local pane_id="$1" timeout="${2:-120}" desc="${3:-cc prompt}"
|
||||
echo -e " \e[36m⏳\e[0m 等待 ${desc}(最多 ${timeout}s)..."
|
||||
for i in $(seq 1 "$timeout"); do
|
||||
local last_lines
|
||||
last_lines=$(tmux capture-pane -t "$pane_id" -p 2>/dev/null | tail -5 || true)
|
||||
if echo "$last_lines" | grep -q '❯'; then
|
||||
echo -e " \e[36m✓\e[0m ${desc} 就绪(等待 ${i}s)"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo -e " \e[31m✗\e[0m ${desc} 超时"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ─── 清理旧 session ───
|
||||
tmux kill-session -t "$SESSION" 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "═══ tmux-send-prompt.sh 集成测试(真实 cc)═══"
|
||||
echo ""
|
||||
|
||||
# ─── 0. 环境检查 ───
|
||||
echo "── 0. 环境准备 ──"
|
||||
command -v tmux &>/dev/null || { echo " ✗ 系统未安装 tmux"; exit 0; }
|
||||
command -v claude &>/dev/null || { echo " ✗ claude 未安装"; exit 0; }
|
||||
echo " ✓ tmux + claude 环境就绪"
|
||||
|
||||
# ─── 1. 创建 tmux session ───
|
||||
echo ""
|
||||
echo "── 1. 创建测试环境 ──"
|
||||
|
||||
tmux new-session -d -s "$SESSION" -x 200 -y 50
|
||||
CC_PANE=$(tmux display-message -t "$SESSION" -p '#{pane_id}')
|
||||
tmux split-window -t "$SESSION" -h
|
||||
CTRL_PANE=$(tmux display-message -t "$SESSION" -p '#{pane_id}')
|
||||
|
||||
echo " ✓ session=$SESSION cc=$CC_PANE ctrl=$CTRL_PANE"
|
||||
|
||||
echo " → 在 $CC_PANE 启动 claude..."
|
||||
tmux send-keys -t "$CC_PANE" "source ~/.bashrc && claude --dangerously-skip-permissions --allow-dangerously-skip-permissions" Enter
|
||||
|
||||
if ! wait_for_prompt "$CC_PANE" 120 "cc 启动"; then
|
||||
echo " ✗ cc 启动失败"
|
||||
tmux capture-pane -t "$CC_PANE" -p | tail -10
|
||||
exit 1
|
||||
fi
|
||||
echo " ✓ cc 启动成功"
|
||||
|
||||
# ─── 2. 生成测试脚本 ───
|
||||
echo ""
|
||||
echo "── 2. 生成测试脚本 ──"
|
||||
|
||||
RUNNER="${TEST_DIR}/runner.sh"
|
||||
|
||||
# 步骤1: 写入 header(单引号 heredoc,不做任何替换)
|
||||
cat > "$RUNNER" <<HEADER
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
CC_PANE="${CC_PANE}"
|
||||
SCRIPT="${SCRIPT}"
|
||||
TEST_DIR="${TEST_DIR}"
|
||||
SESSION="${SESSION}"
|
||||
HEADER
|
||||
|
||||
# 步骤2: 追加颜色定义(用单引号 heredoc 保留 $'...' 原样)
|
||||
cat >> "$RUNNER" <<'COLORS'
|
||||
|
||||
G=$'\e[32m'
|
||||
R=$'\e[31m'
|
||||
Y=$'\e[33m'
|
||||
B=$'\e[1m'
|
||||
N=$'\e[0m'
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
result() {
|
||||
local label="$1" ok="$2" detail="${3:-}"
|
||||
if [[ "$ok" == "PASS" ]]; then
|
||||
((pass++)) || true
|
||||
echo " ${G}✓ PASS${N} ${label}${detail:+ — ${detail}}"
|
||||
else
|
||||
((fail++)) || true
|
||||
echo " ${R}✗ FAIL${N} ${label}${detail:+ — ${detail}}"
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_prompt() {
|
||||
local pane_id="$1" timeout="${2:-60}"
|
||||
for i in $(seq 1 "$timeout"); do
|
||||
tmux capture-pane -t "$pane_id" -p 2>/dev/null | tail -5 | grep -q '❯' && return 0
|
||||
sleep 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_response() {
|
||||
local pane_id="$1" keyword="$2" timeout="${3:-90}"
|
||||
for i in $(seq 1 "$timeout"); do
|
||||
tmux capture-pane -t "$pane_id" -p -S -50 2>/dev/null | grep -qF "$keyword" && { sleep 2; return 0; }
|
||||
sleep 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "${B}═══ 开始测试 ═══${N}"
|
||||
echo ""
|
||||
COLORS
|
||||
|
||||
# 步骤3: 追加测试场景(单引号 heredoc,变量由运行时 bash 解释)
|
||||
cat >> "$RUNNER" <<'SCENARIOS'
|
||||
|
||||
# ── 场景1: 短文本字符串 ──
|
||||
echo "${B}── 场景1: 短文本字符串 ──${N}"
|
||||
bash "$SCRIPT" "$CC_PANE" "请回复 TEST_OK_短文本" 2>&1 | while read -r line; do echo " $line"; done
|
||||
if wait_for_response "$CC_PANE" "TEST_OK_短文本"; then
|
||||
result "短文本 → cc 收到并回复" "PASS"
|
||||
else
|
||||
result "短文本 → cc 收到并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景2: 文件路径 ──
|
||||
echo ""
|
||||
echo "${B}── 场景2: 文件路径 → cc 自行读取 ──${N}"
|
||||
cat > "${TEST_DIR}/test-prompt.md" <<'PROMPT'
|
||||
请回复以下确认码:FILE_OK_读取成功
|
||||
不要做其他任何事情,只回复确认码。
|
||||
PROMPT
|
||||
echo " ✓ 测试文件已创建: ${TEST_DIR}/test-prompt.md"
|
||||
|
||||
bash "$SCRIPT" "$CC_PANE" "${TEST_DIR}/test-prompt.md" 2>&1 | while read -r line; do echo " $line"; done
|
||||
sleep 3
|
||||
if wait_for_response "$CC_PANE" "FILE_OK"; then
|
||||
result "文件路径 → cc 读取文件并回复" "PASS"
|
||||
else
|
||||
result "文件路径 → cc 读取文件并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景3: 相对路径文件 ──
|
||||
echo ""
|
||||
echo "${B}── 场景3: 相对路径文件 ──${N}"
|
||||
mkdir -p "${TEST_DIR}/subdir"
|
||||
cat > "${TEST_DIR}/subdir/relative.md" <<'PROMPT'
|
||||
请回复确认码:RELATIVE_OK
|
||||
PROMPT
|
||||
|
||||
pushd "$TEST_DIR" > /dev/null
|
||||
bash "$SCRIPT" "$CC_PANE" "subdir/relative.md" 2>&1 | while read -r line; do echo " $line"; done
|
||||
popd > /dev/null
|
||||
sleep 3
|
||||
if wait_for_response "$CC_PANE" "RELATIVE_OK"; then
|
||||
result "相对路径 → cc 读取成功" "PASS"
|
||||
else
|
||||
result "相对路径 → cc 读取成功" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景4: 长文本字符串 ──
|
||||
echo ""
|
||||
echo "${B}── 场景4: 长文本字符串(200+ 字)──${N}"
|
||||
LONG_TEXT="请回复确认码:LONG_OK。以下是一段长文本用于测试:密码管理系统需要满足以下安全要求:第一,所有敏感数据必须使用 AES-256-GCM 加密存储;第二,密码哈希使用 Argon2id 算法,参数为 64MB 内存和 3 次迭代;第三,设备认证使用 Ed25519 椭圆曲线签名;第四,传输层使用 TLS 1.3 双向认证;第五,主密码最少 8 位,必须包含大小写字母、数字和特殊符号。请只回复确认码 LONG_OK。"
|
||||
|
||||
bash "$SCRIPT" "$CC_PANE" "$LONG_TEXT" 2>&1 | while read -r line; do echo " $line"; done
|
||||
if wait_for_response "$CC_PANE" "LONG_OK"; then
|
||||
result "长文本(200+字)→ cc 收到并回复" "PASS"
|
||||
else
|
||||
result "长文本(200+字)→ cc 收到并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景5: 特殊字符 ──
|
||||
echo ""
|
||||
echo "${B}── 场景5: 特殊字符文本 ──${N}"
|
||||
SPECIAL_TEXT='请回复确认码:SPECIAL_OK,包含符号:|、&、$、"hello"、(test)、[array]、{json: true}'
|
||||
bash "$SCRIPT" "$CC_PANE" "$SPECIAL_TEXT" 2>&1 | while read -r line; do echo " $line"; done
|
||||
if wait_for_response "$CC_PANE" "SPECIAL_OK"; then
|
||||
result "特殊字符文本 → cc 收到并回复" "PASS"
|
||||
else
|
||||
result "特殊字符文本 → cc 收到并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景6: 自定义 submit-delay ──
|
||||
echo ""
|
||||
echo "${B}── 场景6: 自定义 submit-delay=3 ──${N}"
|
||||
bash "$SCRIPT" "$CC_PANE" "请回复确认码:DELAY_OK" 3 2>&1 | while read -r line; do echo " $line"; done
|
||||
if wait_for_response "$CC_PANE" "DELAY_OK"; then
|
||||
result "自定义 delay=3 → cc 收到并回复" "PASS"
|
||||
else
|
||||
result "自定义 delay=3 → cc 收到并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景7: 多行内容文件 ──
|
||||
echo ""
|
||||
echo "${B}── 场景7: 多行内容文件 ──${N}"
|
||||
cat > "${TEST_DIR}/multiline.md" <<'PROMPT'
|
||||
请按以下步骤回复:
|
||||
|
||||
1. 回复确认码:MULTI_OK
|
||||
2. 不要执行其他任何操作
|
||||
3. 直接回复确认码即可
|
||||
|
||||
感谢配合。
|
||||
PROMPT
|
||||
|
||||
bash "$SCRIPT" "$CC_PANE" "${TEST_DIR}/multiline.md" 2>&1 | while read -r line; do echo " $line"; done
|
||||
sleep 3
|
||||
if wait_for_response "$CC_PANE" "MULTI_OK"; then
|
||||
result "多行文件 → cc 读取并回复" "PASS"
|
||||
else
|
||||
result "多行文件 → cc 读取并回复" "FAIL"
|
||||
fi
|
||||
wait_for_prompt "$CC_PANE" 30
|
||||
|
||||
# ── 场景8: 不存在的路径 ──
|
||||
echo ""
|
||||
echo "${B}── 场景8: 不存在的路径 → 视为文本 ──${N}"
|
||||
bash "$SCRIPT" "$CC_PANE" "请回复确认码:NOTEXIST_OK" 2>&1 | while read -r line; do echo " $line"; done
|
||||
if wait_for_response "$CC_PANE" "NOTEXIST_OK"; then
|
||||
result "不存在路径字符串 → cc 收到并回复" "PASS"
|
||||
else
|
||||
result "不存在路径字符串 → cc 收到并回复" "FAIL"
|
||||
fi
|
||||
|
||||
# ── 结果汇总 ──
|
||||
echo ""
|
||||
echo "════════════════════════════════════"
|
||||
echo " ${G}通过: ${pass}${N} ${R}失败: ${fail}${N} 总计: $((pass + fail))"
|
||||
echo "════════════════════════════════════"
|
||||
echo ""
|
||||
echo "提示: 按 Ctrl+B 再按 D 可脱离 session"
|
||||
echo " 执行 tmux kill-session -t $SESSION 可清理"
|
||||
SCENARIOS
|
||||
|
||||
chmod +x "$RUNNER"
|
||||
echo " ✓ 测试脚本已生成: $RUNNER"
|
||||
|
||||
# ─── 3. 切换到测试 session ───
|
||||
echo ""
|
||||
echo "── 3. 启动测试 → 切换到 session ──"
|
||||
echo " 左 pane: cc(接收命令)"
|
||||
echo " 右 pane: 测试运行器(显示进度)"
|
||||
echo ""
|
||||
echo " ══════════════════════════════════"
|
||||
echo " 即将切换到 tmux session: $SESSION"
|
||||
echo " 按 Ctrl+B 再按 s 可切换回原 session"
|
||||
echo " ══════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# 向 ctrl pane 发送执行命令
|
||||
tmux send-keys -t "$CTRL_PANE" "sleep 1 && bash $RUNNER" Enter
|
||||
|
||||
# 切换到测试 session
|
||||
if [[ -n "${TMUX:-}" ]]; then
|
||||
exec tmux switch-client -t "$SESSION"
|
||||
else
|
||||
exec tmux attach-session -t "$SESSION"
|
||||
fi
|
||||
Reference in New Issue
Block a user