Files
zclaw_openfang/scripts/tests/real-integration-test.sh
iven 54ccc0a7b0 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>
2026-03-21 00:25:32 +08:00

480 lines
15 KiB
Bash
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
# 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