UNPKG

integration-test-mcp

Version:

MCP服务器用于集成测试

248 lines (247 loc) 8.42 kB
/** * 集成测试 MCP 服务器工具函数 */ import os from 'os'; import axios from 'axios'; import puppeteer from 'puppeteer-core'; // 全局配置 export const CONFIG = { // 登录页面URL loginUrl: process.env.MCP_API_BASE_URL || '', // API配置 api: { baseUrl: process.env.MCP_API_BASE_URL || '', featureList: "/brapi/feature/list", submitTest: "/brapi/feature/submit_test", pipelineBranches: "/plapi/branch/get_feature_list", pipelineIntegrate: "/plapi/stage/integrate", headers: { "content-type": "application/json", "group-id": "3a079c60-d2ec-9e36-0135-6112ed2fe6ed", }, pipeline: { taskId: "3a1277fd-8c79-6c90-b9a7-ae75a80b472a", pipelineId: "3a1277f8-a6c1-1c75-7428-4ecd9f1617e7", stageId: "3a1277fd-8c5f-3fca-12f1-81799faf345d", }, }, // 登录凭证 credentials: { selectors: { usernameInput: ".login-user", passwordInput: ".login-pwd", submitButton: ".login-button", }, }, // 需要获取的cookie字段 cookieFields: ["token"], // 登录成功后的判断条件 loginSuccessCondition: { urlIncludes: "/feature", elementExists: ".ant-avatar", }, }; /** * 获取登录凭证 * @returns 返回用户名和密码 * @throws 如果环境变量未设置则抛出错误 */ export function getCredentials() { const username = process.env.MCP_USERNAME; const password = process.env.MCP_PASSWORD; const baseUrl = process.env.MCP_API_BASE_URL; if (!username || !password) { throw new Error('环境变量 MCP_USERNAME 或 MCP_PASSWORD 未设置,请先设置环境变量'); } if (!baseUrl) { throw new Error('环境变量 MCP_API_BASE_URL 未设置,请先设置环境变量'); } return { username, password }; } export function createApiClient(token) { const client = axios.create({ baseURL: CONFIG.api.baseUrl, headers: { ...CONFIG.api.headers, Cookie: `token=${token}`, }, }); client.interceptors.response.use((response) => response.data, (error) => { throw new Error(`API请求失败: ${error.response?.data?.msg || error.message}`); }); return client; } export async function getFeatureList(apiClient, branchName) { const params = { page_size: 100, page: 1, show_myself: 1, name: branchName, }; const response = await apiClient.get(CONFIG.api.featureList, { params }); if (response.code !== 0) { throw new Error(response.msg || "获取特性列表失败"); } if (!response.data.items?.length) { throw new Error(`未找到分支 ${branchName} 对应的特性数据`); } return response; } export async function submitFeatureToTest(apiClient, featureId) { const data = { id: featureId, action: "submit_test", info: "1", }; const response = await apiClient.post(CONFIG.api.submitTest, data); if (response.code === 10000) { throw new Error(response.msg || "提测失败"); } if (response.code !== 0) { throw new Error(response.msg || "提交特性到测试失败"); } return response; } export async function getPipelineBranches(apiClient, branchName) { const params = { task_id: CONFIG.api.pipeline.taskId, pipeline_id: CONFIG.api.pipeline.pipelineId, page: 1, page_size: 10, name: branchName, }; const response = await apiClient.get(CONFIG.api.pipelineBranches, { params, }); if (response.code !== 0) { throw new Error(response.msg || "获取流水线分支列表失败"); } if (!response.data.items?.length) { throw new Error(`未找到分支 ${branchName} 对应的流水线数据`); } return response; } export async function integratePipeline(apiClient, featureId) { const data = { pipeline_id: CONFIG.api.pipeline.pipelineId, stage_id: CONFIG.api.pipeline.stageId, task_id: CONFIG.api.pipeline.taskId, feature_ids: featureId, }; const response = await apiClient.post(CONFIG.api.pipelineIntegrate, data); if (response.code !== 0) { throw new Error(response.msg || "执行流水线集成失败"); } return response; } export function getEdgePath() { const platform = os.platform(); switch (platform) { case "win32": return "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"; case "darwin": return "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"; case "linux": return "/usr/bin/microsoft-edge"; default: throw new Error(`不支持的操作系统: ${platform}`); } } export async function loginAndGetCookies() { let browserInstance = null; try { const launchOptions = { headless: true, defaultViewport: { width: 1920, height: 1080, }, args: [ "--disable-gpu", "--disable-dev-shm-usage", "--disable-setuid-sandbox", "--no-sandbox", ], executablePath: getEdgePath(), }; // 获取登录凭证 const { username, password } = getCredentials(); browserInstance = await puppeteer.launch(launchOptions); const page = await browserInstance.newPage(); await page.goto(CONFIG.loginUrl, { waitUntil: "networkidle2" }); await page.type(CONFIG.credentials.selectors.usernameInput, username); await page.type(CONFIG.credentials.selectors.passwordInput, password); await page.click(CONFIG.credentials.selectors.submitButton); if (CONFIG.loginSuccessCondition.urlIncludes) { await page.waitForFunction((expectedUrl) => window.location.href.includes(expectedUrl), {}, CONFIG.loginSuccessCondition.urlIncludes); } if (CONFIG.loginSuccessCondition.elementExists) { await page.waitForSelector(CONFIG.loginSuccessCondition.elementExists); } const cookies = await page.cookies(); const result = {}; for (const cookie of cookies) { if (CONFIG.cookieFields.includes(cookie.name)) { result[cookie.name] = cookie.value; } } return result; } catch (error) { throw new Error(`登录过程中发生错误: ${error.message}`); } finally { if (browserInstance) { try { await browserInstance.close(); } catch (closeError) { console.error("关闭浏览器时发生错误:", closeError.message); } } } } // 主要业务逻辑 export async function runIntegrationTest(branchName) { try { const cookies = await loginAndGetCookies(); const apiClient = createApiClient(cookies.token); const featureList = await getFeatureList(apiClient, branchName); const feature = featureList.data.items[0]; const submitResult = await submitFeatureToTest(apiClient, feature.id); const pipelineBranches = await getPipelineBranches(apiClient, branchName); const branch = pipelineBranches.data.items[0]; const integrateResult = await integratePipeline(apiClient, branch.id); return { success: true, branch: branchName, feature: { id: feature.id, name: feature.name, branch_name: feature.branch_name, status: feature.status, }, submit: { code: submitResult.code, msg: submitResult.msg, success: submitResult.data, }, pipeline: { id: branch.id, name: branch.name, status: branch.status, }, integrate: { code: integrateResult.code, msg: integrateResult.msg, success: integrateResult.data, }, }; } catch (error) { return { success: false, error: error.message, }; } }