# ZCLAW 真实环境集成测试 (Windows PowerShell) # 连接真实 ZCLAW Kernel 验证完整数据流 # # 使用方法: # 1. 确保 ZCLAW Kernel 正在运行: zclaw start # 2. 设置 API Key: $env:ZHIPU_API_KEY="your_key" # 3. 运行测试: .\scripts\tests\real-integration-test.ps1 param( [string]$GatewayHost = "127.0.0.1", [int]$GatewayPort = 50051, [switch]$Verbose ) # 配置 $GatewayUrl = "http://${GatewayHost}:${GatewayPort}" $Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $ResultsDir = "test-results/integration" $LogFile = "$ResultsDir/integration_$Timestamp.log" # 测试计数器 $script:TestsRun = 0 $script:TestsPassed = 0 $script:TestsFailed = 0 $script:TestsSkipped = 0 # 创建结果目录 if (-not (Test-Path $ResultsDir)) { New-Item -ItemType Directory -Path $ResultsDir -Force | Out-Null } # 日志函数 function Write-Log { param([string]$Message) Write-Host $Message Add-Content -Path $LogFile -Value $Message } function Write-TestResult { param( [string]$Id, [string]$Description, [string]$Status, [string]$Details = "" ) $script:TestsRun++ switch ($Status) { "PASS" { $script:TestsPassed++ Write-Log "${Green}✅ [$Id] $Description${Reset}" } "FAIL" { $script:TestsFailed++ Write-Log "${Red}❌ [$Id] $Description${Reset}" } "SKIP" { $script:TestsSkipped++ Write-Log "${Yellow}⏭️ [$Id] $Description (跳过)${Reset}" } } if ($Details) { Write-Log " $Details" } } # 颜色定义 $Red = "`e[0;31m" $Green = "`e[0;32m" $Yellow = "`e[1;33m" $Blue = "`e[0;34m" $Reset = "`e[0m" # ============================================================================= # 测试开始 # ============================================================================= Write-Log "${Blue}========================================${Reset}" Write-Log "${Blue} ZCLAW 真实环境集成测试 (Windows)${Reset}" Write-Log "${Blue}========================================${Reset}" Write-Log "" Write-Log "测试时间: $(Get-Date)" Write-Log "Gateway URL: $GatewayUrl" Write-Log "日志文件: $LogFile" Write-Log "" # ============================================================================= # 1. 环境检查 # ============================================================================= Write-Log "${Yellow}[1. 环境检查]${Reset}" # RI-ENV-01: 检查 PowerShell 版本 $PSVersionTable.PSVersion Write-TestResult "RI-ENV-01" "PowerShell 版本 $($PSVersionTable.PSVersion)" "PASS" # RI-ENV-02: 检查 curl (Invoke-WebRequest) try { $null = Get-Command Invoke-WebRequest -ErrorAction Stop Write-TestResult "RI-ENV-02" "Invoke-WebRequest 可用" "PASS" } catch { Write-TestResult "RI-ENV-02" "Invoke-WebRequest 可用" "FAIL" exit 1 } # RI-ENV-03: 检查 Node.js try { $nodeVersion = node -v Write-TestResult "RI-ENV-03" "Node.js 可用 ($nodeVersion)" "PASS" } catch { Write-TestResult "RI-ENV-03" "Node.js 可用" "FAIL" "需要安装 Node.js" exit 1 } Write-Log "" # ============================================================================= # 2. Gateway 连接测试 # ============================================================================= Write-Log "${Yellow}[2. Gateway 连接测试]${Reset}" # RI-GW-01: 检查端口可达性 try { $tcpClient = New-Object System.Net.Sockets.TcpClient $connect = $tcpClient.BeginConnect($GatewayHost, $GatewayPort, $null, $null) $wait = $connect.AsyncWaitHandle.WaitOne(5000) if ($wait -and $tcpClient.Connected) { Write-TestResult "RI-GW-01" "Gateway 端口 $GatewayPort 可达" "PASS" $tcpClient.EndConnect($connect) } else { Write-TestResult "RI-GW-01" "Gateway 端口 $GatewayPort 可达" "FAIL" "请确保 ZCLAW 正在运行: zclaw start" } $tcpClient.Close() } catch { Write-TestResult "RI-GW-01" "Gateway 端口 $GatewayPort 可达" "FAIL" $_.Exception.Message } # RI-GW-02: Health 端点 try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/health" -Method Get -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { Write-TestResult "RI-GW-02" "Health 端点返回 200" "PASS" "响应: $($response.Content)" } else { Write-TestResult "RI-GW-02" "Health 端点返回 200" "FAIL" "HTTP $($response.StatusCode)" } } catch { Write-TestResult "RI-GW-02" "Health 端点返回 200" "FAIL" $_.Exception.Message } # RI-GW-03: Health 响应结构 try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/health" -Method Get -TimeoutSec 10 -ErrorAction Stop $content = $response.Content | ConvertFrom-Json if ($content.status) { Write-TestResult "RI-GW-03" "Health 响应包含 status 字段" "PASS" } else { Write-TestResult "RI-GW-03" "Health 响应包含 status 字段" "FAIL" "响应: $($response.Content)" } } catch { Write-TestResult "RI-GW-03" "Health 响应包含 status 字段" "FAIL" $_.Exception.Message } Write-Log "" # ============================================================================= # 3. 模型配置测试 # ============================================================================= Write-Log "${Yellow}[3. 模型配置测试]${Reset}" # RI-MOD-01: 获取可用模型列表 try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/models" -Method Get -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { Write-TestResult "RI-MOD-01" "Models 端点返回 200" "PASS" $models = $response.Content | ConvertFrom-Json $modelCount = ($models | Measure-Object).Count if ($modelCount -gt 0) { Write-TestResult "RI-MOD-02" "检测到 $modelCount 个可用模型" "PASS" } else { Write-TestResult "RI-MOD-02" "检测到可用模型" "FAIL" "响应: $($response.Content)" } } else { Write-TestResult "RI-MOD-01" "Models 端点返回 200" "FAIL" "HTTP $($response.StatusCode)" Write-TestResult "RI-MOD-02" "检测到可用模型" "SKIP" } } catch { Write-TestResult "RI-MOD-01" "Models 端点返回 200" "FAIL" $_.Exception.Message Write-TestResult "RI-MOD-02" "检测到可用模型" "SKIP" } # RI-MOD-03: 检查中文模型配置 if (Test-Path "config/chinese-providers.toml") { Write-TestResult "RI-MOD-03" "中文模型配置文件存在" "PASS" } else { Write-TestResult "RI-MOD-03" "中文模型配置文件存在" "FAIL" "缺少 config/chinese-providers.toml" } Write-Log "" # ============================================================================= # 4. Agent 管理测试 # ============================================================================= Write-Log "${Yellow}[4. Agent 管理测试]${Reset}" # RI-AGT-01: 获取 Agent 列表 try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/agents" -Method Get -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { Write-TestResult "RI-AGT-01" "Agents 端点返回 200" "PASS" $agents = $response.Content | ConvertFrom-Json if ($agents -and ($agents.id -or $agents.name)) { Write-TestResult "RI-AGT-02" "检测到 Agent 配置" "PASS" } else { Write-TestResult "RI-AGT-02" "检测到 Agent 配置" "FAIL" "响应: $($response.Content)" } } else { Write-TestResult "RI-AGT-01" "Agents 端点返回 200" "FAIL" "HTTP $($response.StatusCode)" } } catch { Write-TestResult "RI-AGT-01" "Agents 端点返回 200" "FAIL" $_.Exception.Message } Write-Log "" # ============================================================================= # 5. API Key 验证测试 # ============================================================================= Write-Log "${Yellow}[5. API Key 验证测试]${Reset}" # RI-KEY-01: 检查智谱 API Key if ($env:ZHIPU_API_KEY) { Write-TestResult "RI-KEY-01" "智谱 API Key 已设置" "PASS" "长度: $($env:ZHIPU_API_KEY.Length) 字符" } else { Write-TestResult "RI-KEY-01" "智谱 API Key 已设置" "FAIL" "请设置: `$env:ZHIPU_API_KEY='your_key'" } # RI-KEY-02: 检查通义千问 API Key if ($env:DASHSCOPE_API_KEY) { Write-TestResult "RI-KEY-02" "通义千问 API Key 已设置" "PASS" } else { Write-TestResult "RI-KEY-02" "通义千问 API Key 已设置" "SKIP" "可选" } # RI-KEY-03: 检查 Kimi API Key if ($env:MOONSHOT_API_KEY) { Write-TestResult "RI-KEY-03" "Kimi API Key 已设置" "PASS" } else { Write-TestResult "RI-KEY-03" "Kimi API Key 已设置" "SKIP" "可选" } Write-Log "" # ============================================================================= # 6. 对话功能测试(需要 API Key) # ============================================================================= Write-Log "${Yellow}[6. 对话功能测试]${Reset}" if ($env:ZHIPU_API_KEY) { # RI-CHAT-01: 发送测试消息 $chatPayload = @{ messages = @( @{ role = "user" content = "你好,这是一个测试消息。请简短回复。" } ) model = "glm-4-flash" stream = $false } | ConvertTo-Json -Depth 3 Write-Log "发送测试消息..." try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/chat" ` -Method Post ` -ContentType "application/json" ` -Body $chatPayload ` -TimeoutSec 60 ` -ErrorAction Stop if ($response.StatusCode -eq 200) { Write-TestResult "RI-CHAT-01" "对话请求成功" "PASS" $chatResult = $response.Content | ConvertFrom-Json if ($chatResult.content -or $chatResult.text -or $chatResult.message) { Write-TestResult "RI-CHAT-02" "对话响应包含内容" "PASS" } else { Write-TestResult "RI-CHAT-02" "对话响应包含内容" "FAIL" "响应: $($response.Content)" } } else { Write-TestResult "RI-CHAT-01" "对话请求成功" "FAIL" "HTTP $($response.StatusCode)" Write-TestResult "RI-CHAT-02" "对话响应包含内容" "SKIP" } } catch { Write-TestResult "RI-CHAT-01" "对话请求成功" "FAIL" $_.Exception.Message Write-TestResult "RI-CHAT-02" "对话响应包含内容" "SKIP" } } else { Write-TestResult "RI-CHAT-01" "对话请求成功" "SKIP" "需要设置 ZHIPU_API_KEY" Write-TestResult "RI-CHAT-02" "对话响应包含内容" "SKIP" } Write-Log "" # ============================================================================= # 7. Hands 触发测试 # ============================================================================= Write-Log "${Yellow}[7. Hands 触发测试]${Reset}" # RI-HAND-01: 获取可用 Hands try { $response = Invoke-WebRequest -Uri "$GatewayUrl/api/hands" -Method Get -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { Write-TestResult "RI-HAND-01" "Hands 端点返回 200" "PASS" $hands = $response.Content | ConvertFrom-Json $handCount = ($hands | Measure-Object).Count if ($handCount -gt 0) { Write-TestResult "RI-HAND-02" "检测到 $handCount 个可用 Hands" "PASS" } else { Write-TestResult "RI-HAND-02" "检测到可用 Hands" "SKIP" "无 Hands 配置" } } else { Write-TestResult "RI-HAND-01" "Hands 端点返回 200" "FAIL" "HTTP $($response.StatusCode)" Write-TestResult "RI-HAND-02" "检测到可用 Hands" "SKIP" } } catch { Write-TestResult "RI-HAND-01" "Hands 端点返回 200" "SKIP" "端点可能未实现" Write-TestResult "RI-HAND-02" "检测到可用 Hands" "SKIP" } Write-Log "" # ============================================================================= # 8. 记忆持久化测试 # ============================================================================= Write-Log "${Yellow}[8. 记忆持久化测试]${Reset}" $memoryDir = "$env:USERPROFILE\.zclaw\data\memory" # RI-MEM-01: 检查记忆存储目录 if (Test-Path $memoryDir) { Write-TestResult "RI-MEM-01" "记忆存储目录存在" "PASS" $memoryFiles = Get-ChildItem -Path $memoryDir -Filter "*.json" -ErrorAction SilentlyContinue $memoryCount = ($memoryFiles | Measure-Object).Count if ($memoryCount -gt 0) { Write-TestResult "RI-MEM-02" "检测到 $memoryCount 个记忆文件" "PASS" } else { Write-TestResult "RI-MEM-02" "检测到记忆文件" "SKIP" "尚无记忆数据" } } else { Write-TestResult "RI-MEM-01" "记忆存储目录存在" "FAIL" "目录: $memoryDir" Write-TestResult "RI-MEM-02" "检测到记忆文件" "SKIP" } Write-Log "" # ============================================================================= # 9. 配置验证测试 # ============================================================================= Write-Log "${Yellow}[9. 配置验证测试]${Reset}" # RI-CFG-01: 主配置文件 if (Test-Path "config/config.toml") { Write-TestResult "RI-CFG-01" "主配置文件存在" "PASS" } else { Write-TestResult "RI-CFG-01" "主配置文件存在" "FAIL" } # RI-CFG-02: ZCLAW 配置文件 $zclawConfig = "$env:USERPROFILE\.zclaw\config.toml" if (Test-Path $zclawConfig) { Write-TestResult "RI-CFG-02" "ZCLAW 配置文件存在" "PASS" } else { Write-TestResult "RI-CFG-02" "ZCLAW 配置文件存在" "FAIL" "请运行: zclaw init" } # RI-CFG-03: 检查前端依赖 if (Test-Path "desktop\node_modules") { Write-TestResult "RI-CFG-03" "前端依赖已安装" "PASS" } else { Write-TestResult "RI-CFG-03" "前端依赖已安装" "FAIL" "请运行: cd desktop; pnpm install" } Write-Log "" # ============================================================================= # 10. 前端构建测试 # ============================================================================= Write-Log "${Yellow}[10. 前端构建测试]${Reset}" # RI-UI-01: 检查 Tauri 配置 if (Test-Path "desktop\src-tauri\tauri.conf.json") { Write-TestResult "RI-UI-01" "Tauri 配置文件存在" "PASS" } else { Write-TestResult "RI-UI-01" "Tauri 配置文件存在" "FAIL" } # RI-UI-02: 检查 package.json if (Test-Path "desktop\package.json") { Write-TestResult "RI-UI-02" "前端 package.json 存在" "PASS" } else { Write-TestResult "RI-UI-02" "前端 package.json 存在" "FAIL" } Write-Log "" # ============================================================================= # 测试总结 # ============================================================================= Write-Log "${Blue}========================================${Reset}" Write-Log "${Blue} 测试总结${Reset}" Write-Log "${Blue}========================================${Reset}" Write-Log "" Write-Log "总测试数: $script:TestsRun" Write-Log "${Green}通过: $script:TestsPassed${Reset}" Write-Log "${Red}失败: $script:TestsFailed${Reset}" Write-Log "${Yellow}跳过: $script:TestsSkipped${Reset}" Write-Log "" # 计算成功率 if ($script:TestsRun -gt 0) { $successRate = [math]::Round(($script:TestsPassed / $script:TestsRun) * 100, 2) } else { $successRate = 0 } # 生成 JSON 报告 $reportFile = "$ResultsDir/report_$Timestamp.json" $report = @{ timestamp = (Get-Date -Format "o") gateway_url = $GatewayUrl summary = @{ total = $script:TestsRun passed = $script:TestsPassed failed = $script:TestsFailed skipped = $script:TestsSkipped } success_rate = $successRate log_file = $LogFile } | ConvertTo-Json -Depth 3 $report | Out-File -FilePath $reportFile -Encoding UTF8 Write-Log "报告已保存到: $reportFile" Write-Log "日志已保存到: $LogFile" Write-Log "" # 退出码 if ($script:TestsFailed -gt 0) { Write-Log "${Red}存在失败的测试,请检查上述详情${Reset}" exit 1 } else { Write-Log "${Green}所有测试通过!${Reset}" exit 0 }