Files
team/scripts/test-tmux-send-prompt-integ.sh
T
2026-04-19 21:47:08 +08:00

286 lines
9.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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