feat(test): add real environment integration test scripts

- Add Bash version (real-integration-test.sh) for Linux/macOS
- Add PowerShell version (real-integration-test.ps1) for Windows
- Tests cover: Gateway connection, Model config, Agent management, API Key validation, Chat functionality, Hands triggers, Memory persistence, Configuration validation
- Update plan file to reflect P0 progress and completed P2 tasks

These scripts enable validation against real OpenFang Kernel instead of mocks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-21 00:25:32 +08:00
parent d3a4de2480
commit 54ccc0a7b0
3 changed files with 999 additions and 27 deletions

View File

@@ -0,0 +1,479 @@
#!/bin/bash
# ZCLAW 真实环境集成测试
# 连接真实 OpenFang Kernel 验证完整数据流
#
# 使用方法:
# 1. 确保 OpenFang Kernel 正在运行: openfang start
# 2. 设置 API Key: export ZHIPU_API_KEY=your_key
# 3. 运行测试: ./scripts/tests/real-integration-test.sh
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 配置
GATEWAY_HOST="${GATEWAY_HOST:-127.0.0.1}"
GATEWAY_PORT="${GATEWAY_PORT:-50051}"
GATEWAY_URL="http://$GATEWAY_HOST:$GATEWAY_PORT"
RESULTS_DIR="test-results/integration"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$RESULTS_DIR/integration_$TIMESTAMP.log"
# 测试计数器
TESTS_RUN=0
TESTS_PASSED=0
TESTS_FAILED=0
TESTS_SKIPPED=0
# 创建结果目录
mkdir -p "$RESULTS_DIR"
# 日志函数
log() {
echo -e "$1" | tee -a "$LOG_FILE"
}
log_test() {
local id="$1"
local description="$2"
local status="$3"
local details="${4:-}"
TESTS_RUN=$((TESTS_RUN + 1))
case "$status" in
PASS)
TESTS_PASSED=$((TESTS_PASSED + 1))
log "${GREEN}✅ [$id] $description${NC}"
;;
FAIL)
TESTS_FAILED=$((TESTS_FAILED + 1))
log "${RED}❌ [$id] $description${NC}"
;;
SKIP)
TESTS_SKIPPED=$((TESTS_SKIPPED + 1))
log "${YELLOW}⏭️ [$id] $description (跳过)${NC}"
;;
esac
if [ -n "$details" ]; then
echo " $details" | tee -a "$LOG_FILE"
fi
}
# 检查命令是否存在
check_command() {
command -v "$1" >/dev/null 2>&1
}
# HTTP 请求辅助函数
http_get() {
curl -s -w "\n%{http_code}" "$1" 2>/dev/null
}
http_post() {
curl -s -w "\n%{http_code}" -X POST -H "Content-Type: application/json" -d "$2" "$1" 2>/dev/null
}
# =============================================================================
# 测试开始
# =============================================================================
log "${BLUE}========================================${NC}"
log "${BLUE} ZCLAW 真实环境集成测试${NC}"
log "${BLUE}========================================${NC}"
log ""
log "测试时间: $(date)"
log "Gateway URL: $GATEWAY_URL"
log "日志文件: $LOG_FILE"
log ""
# =============================================================================
# 1. 环境检查
# =============================================================================
log "${YELLOW}[1. 环境检查]${NC}"
# RI-ENV-01: 检查 curl
if check_command curl; then
log_test "RI-ENV-01" "curl 可用" "PASS"
else
log_test "RI-ENV-01" "curl 可用" "FAIL" "需要安装 curl"
exit 1
fi
# RI-ENV-02: 检查 jq (可选,用于 JSON 解析)
if check_command jq; then
log_test "RI-ENV-02" "jq 可用" "PASS"
HAS_JQ=true
else
log_test "RI-ENV-02" "jq 可用" "SKIP" "建议安装 jq 以获得更好的 JSON 解析"
HAS_JQ=false
fi
# RI-ENV-03: 检查 Node.js
if check_command node; then
NODE_VERSION=$(node -v)
log_test "RI-ENV-03" "Node.js 可用 ($NODE_VERSION)" "PASS"
else
log_test "RI-ENV-03" "Node.js 可用" "FAIL" "需要安装 Node.js"
exit 1
fi
log ""
# =============================================================================
# 2. Gateway 连接测试
# =============================================================================
log "${YELLOW}[2. Gateway 连接测试]${NC}"
# RI-GW-01: 检查端口可达性
if check_command nc; then
if nc -z -w5 "$GATEWAY_HOST" "$GATEWAY_PORT" 2>/dev/null; then
log_test "RI-GW-01" "Gateway 端口 $GATEWAY_PORT 可达" "PASS"
else
log_test "RI-GW-01" "Gateway 端口 $GATEWAY_PORT 可达" "FAIL" "请确保 OpenFang 正在运行: openfang start"
fi
else
log_test "RI-GW-01" "Gateway 端口可达性" "SKIP" "nc 命令不可用"
fi
# RI-GW-02: Health 端点
RESPONSE=$(http_get "$GATEWAY_URL/api/health")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "200" ]; then
log_test "RI-GW-02" "Health 端点返回 200" "PASS" "响应: $BODY"
else
log_test "RI-GW-02" "Health 端点返回 200" "FAIL" "HTTP $HTTP_CODE"
fi
# RI-GW-03: Health 响应结构
if [ "$HTTP_CODE" = "200" ]; then
if echo "$BODY" | grep -q '"status"'; then
log_test "RI-GW-03" "Health 响应包含 status 字段" "PASS"
else
log_test "RI-GW-03" "Health 响应包含 status 字段" "FAIL" "响应: $BODY"
fi
fi
log ""
# =============================================================================
# 3. 模型配置测试
# =============================================================================
log "${YELLOW}[3. 模型配置测试]${NC}"
# RI-MOD-01: 获取可用模型列表
RESPONSE=$(http_get "$GATEWAY_URL/api/models")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "200" ]; then
log_test "RI-MOD-01" "Models 端点返回 200" "PASS"
# 检查是否有模型
if echo "$BODY" | grep -q '"id"'; then
MODEL_COUNT=$(echo "$BODY" | grep -o '"id"' | wc -l)
log_test "RI-MOD-02" "检测到 $MODEL_COUNT 个可用模型" "PASS"
else
log_test "RI-MOD-02" "检测到可用模型" "FAIL" "响应: $BODY"
fi
else
log_test "RI-MOD-01" "Models 端点返回 200" "FAIL" "HTTP $HTTP_CODE"
log_test "RI-MOD-02" "检测到可用模型" "SKIP"
fi
# RI-MOD-03: 检查中文模型配置
if [ -f "config/chinese-providers.toml" ]; then
log_test "RI-MOD-03" "中文模型配置文件存在" "PASS"
else
log_test "RI-MOD-03" "中文模型配置文件存在" "FAIL" "缺少 config/chinese-providers.toml"
fi
log ""
# =============================================================================
# 4. Agent 管理测试
# =============================================================================
log "${YELLOW}[4. Agent 管理测试]${NC}"
# RI-AGT-01: 获取 Agent 列表
RESPONSE=$(http_get "$GATEWAY_URL/api/agents")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "200" ]; then
log_test "RI-AGT-01" "Agents 端点返回 200" "PASS"
else
log_test "RI-AGT-01" "Agents 端点返回 200" "FAIL" "HTTP $HTTP_CODE"
fi
# RI-AGT-02: 检查默认 Agent
if [ "$HTTP_CODE" = "200" ]; then
if echo "$BODY" | grep -q '"id"\|"name"'; then
log_test "RI-AGT-02" "检测到 Agent 配置" "PASS"
else
log_test "RI-AGT-02" "检测到 Agent 配置" "FAIL" "响应: $BODY"
fi
fi
log ""
# =============================================================================
# 5. API Key 验证测试
# =============================================================================
log "${YELLOW}[5. API Key 验证测试]${NC}"
# RI-KEY-01: 检查智谱 API Key
if [ -n "$ZHIPU_API_KEY" ]; then
log_test "RI-KEY-01" "智谱 API Key 已设置" "PASS" "长度: ${#ZHIPU_API_KEY} 字符"
else
log_test "RI-KEY-01" "智谱 API Key 已设置" "FAIL" "请设置: export ZHIPU_API_KEY=your_key"
fi
# RI-KEY-02: 检查通义千问 API Key
if [ -n "$DASHSCOPE_API_KEY" ]; then
log_test "RI-KEY-02" "通义千问 API Key 已设置" "PASS"
else
log_test "RI-KEY-02" "通义千问 API Key 已设置" "SKIP" "可选: export DASHSCOPE_API_KEY=your_key"
fi
# RI-KEY-03: 检查 Kimi API Key
if [ -n "$MOONSHOT_API_KEY" ]; then
log_test "RI-KEY-03" "Kimi API Key 已设置" "PASS"
else
log_test "RI-KEY-03" "Kimi API Key 已设置" "SKIP" "可选: export MOONSHOT_API_KEY=your_key"
fi
log ""
# =============================================================================
# 6. 对话功能测试(需要 API Key
# =============================================================================
log "${YELLOW}[6. 对话功能测试]${NC}"
if [ -n "$ZHIPU_API_KEY" ]; then
# RI-CHAT-01: 发送测试消息
TEST_MESSAGE="你好,这是一个测试消息。请简短回复。"
CHAT_PAYLOAD="{\"messages\":[{\"role\":\"user\",\"content\":\"$TEST_MESSAGE\"}],\"model\":\"glm-4-flash\",\"stream\":false}"
log "发送测试消息: $TEST_MESSAGE"
RESPONSE=$(http_post "$GATEWAY_URL/api/chat" "$CHAT_PAYLOAD")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "200" ]; then
log_test "RI-CHAT-01" "对话请求成功" "PASS"
# 检查响应内容
if echo "$BODY" | grep -q '"content"\|"text"\|"message"'; then
log_test "RI-CHAT-02" "对话响应包含内容" "PASS"
# 显示响应摘要
if [ "$HAS_JQ" = true ]; then
CONTENT=$(echo "$BODY" | jq -r '.content // .text // .message // .choices[0].message.content // empty' 2>/dev/null | head -c 100)
if [ -n "$CONTENT" ]; then
log " 响应摘要: ${CONTENT}..."
fi
fi
else
log_test "RI-CHAT-02" "对话响应包含内容" "FAIL" "响应: $BODY"
fi
else
log_test "RI-CHAT-01" "对话请求成功" "FAIL" "HTTP $HTTP_CODE, 响应: $BODY"
log_test "RI-CHAT-02" "对话响应包含内容" "SKIP"
fi
else
log_test "RI-CHAT-01" "对话请求成功" "SKIP" "需要设置 ZHIPU_API_KEY"
log_test "RI-CHAT-02" "对话响应包含内容" "SKIP"
fi
log ""
# =============================================================================
# 7. Hands 触发测试
# =============================================================================
log "${YELLOW}[7. Hands 触发测试]${NC}"
# RI-HAND-01: 获取可用 Hands
RESPONSE=$(http_get "$GATEWAY_URL/api/hands")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "200" ]; then
log_test "RI-HAND-01" "Hands 端点返回 200" "PASS"
# 检查可用的 Hands
if echo "$BODY" | grep -q '"name"\|"id"'; then
HAND_COUNT=$(echo "$BODY" | grep -o '"name"' | wc -l)
log_test "RI-HAND-02" "检测到 $HAND_COUNT 个可用 Hands" "PASS"
else
log_test "RI-HAND-02" "检测到可用 Hands" "SKIP" "无 Hands 配置"
fi
else
log_test "RI-HAND-01" "Hands 端点返回 200" "FAIL" "HTTP $HTTP_CODE (端点可能未实现)"
log_test "RI-HAND-02" "检测到可用 Hands" "SKIP"
fi
log ""
# =============================================================================
# 8. 记忆持久化测试
# =============================================================================
log "${YELLOW}[8. 记忆持久化测试]${NC}"
# RI-MEM-01: 检查记忆存储目录
MEMORY_DIR="$HOME/.openfang/data/memory"
if [ -d "$MEMORY_DIR" ]; then
log_test "RI-MEM-01" "记忆存储目录存在" "PASS"
# 检查记忆文件
MEMORY_COUNT=$(find "$MEMORY_DIR" -name "*.json" 2>/dev/null | wc -l)
if [ "$MEMORY_COUNT" -gt 0 ]; then
log_test "RI-MEM-02" "检测到 $MEMORY_COUNT 个记忆文件" "PASS"
else
log_test "RI-MEM-02" "检测到记忆文件" "SKIP" "尚无记忆数据"
fi
else
log_test "RI-MEM-01" "记忆存储目录存在" "FAIL" "目录: $MEMORY_DIR"
log_test "RI-MEM-02" "检测到记忆文件" "SKIP"
fi
log ""
# =============================================================================
# 9. 配置验证测试
# =============================================================================
log "${YELLOW}[9. 配置验证测试]${NC}"
# RI-CFG-01: 主配置文件
if [ -f "config/config.toml" ]; then
log_test "RI-CFG-01" "主配置文件存在" "PASS"
else
log_test "RI-CFG-01" "主配置文件存在" "FAIL"
fi
# RI-CFG-02: 检查配置文件语法
if [ -f "config/config.toml" ] && check_command node; then
if node -e "const fs = require('fs'); const content = fs.readFileSync('config/config.toml', 'utf-8'); if (content.includes('[') && content.includes('=')) process.exit(0); else process.exit(1);" 2>/dev/null; then
log_test "RI-CFG-02" "主配置文件语法正确" "PASS"
else
log_test "RI-CFG-02" "主配置文件语法正确" "FAIL"
fi
else
log_test "RI-CFG-02" "主配置文件语法正确" "SKIP"
fi
# RI-CFG-03: OpenFang 配置文件
OPENFANG_CONFIG="$HOME/.openfang/config.toml"
if [ -f "$OPENFANG_CONFIG" ]; then
log_test "RI-CFG-03" "OpenFang 配置文件存在" "PASS"
else
log_test "RI-CFG-03" "OpenFang 配置文件存在" "FAIL" "请运行: openfang init"
fi
log ""
# =============================================================================
# 10. WebSocket 连接测试
# =============================================================================
log "${YELLOW}[10. WebSocket 连接测试]${NC}"
# RI-WS-01: WebSocket 升级检查
WS_RESPONSE=$(curl -s -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
-H "Sec-WebSocket-Version: 13" \
"$GATEWAY_URL/ws" 2>/dev/null | head -1)
if echo "$WS_RESPONSE" | grep -q "101"; then
log_test "RI-WS-01" "WebSocket 升级返回 101" "PASS"
else
log_test "RI-WS-01" "WebSocket 升级返回 101" "SKIP" "可能需要特定端点"
fi
log ""
# =============================================================================
# 11. 前端构建测试
# =============================================================================
log "${YELLOW}[11. 前端构建测试]${NC}"
# RI-UI-01: 检查前端依赖
if [ -d "desktop/node_modules" ]; then
log_test "RI-UI-01" "前端依赖已安装" "PASS"
else
log_test "RI-UI-01" "前端依赖已安装" "FAIL" "请运行: cd desktop && pnpm install"
fi
# RI-UI-02: 检查 Tauri 配置
if [ -f "desktop/src-tauri/tauri.conf.json" ]; then
log_test "RI-UI-02" "Tauri 配置文件存在" "PASS"
else
log_test "RI-UI-02" "Tauri 配置文件存在" "FAIL"
fi
log ""
# =============================================================================
# 测试总结
# =============================================================================
log "${BLUE}========================================${NC}"
log "${BLUE} 测试总结${NC}"
log "${BLUE}========================================${NC}"
log ""
log "总测试数: $TESTS_RUN"
log "${GREEN}通过: $TESTS_PASSED${NC}"
log "${RED}失败: $TESTS_FAILED${NC}"
log "${YELLOW}跳过: $TESTS_SKIPPED${NC}"
log ""
# 生成 JSON 报告
REPORT_FILE="$RESULTS_DIR/report_$TIMESTAMP.json"
cat > "$REPORT_FILE" << EOF
{
"timestamp": "$(date -Iseconds)",
"gateway_url": "$GATEWAY_URL",
"summary": {
"total": $TESTS_RUN,
"passed": $TESTS_PASSED,
"failed": $TESTS_FAILED,
"skipped": $TESTS_SKIPPED
},
"success_rate": $(echo "scale=2; $TESTS_PASSED * 100 / $TESTS_RUN" | bc 2>/dev/null || echo "0"),
"log_file": "$LOG_FILE"
}
EOF
log "报告已保存到: $REPORT_FILE"
log "日志已保存到: $LOG_FILE"
log ""
# 退出码
if [ $TESTS_FAILED -gt 0 ]; then
log "${RED}存在失败的测试,请检查上述详情${NC}"
exit 1
else
log "${GREEN}所有测试通过!${NC}"
exit 0
fi