chore: remove performance tests from CI/CD pipelines

- Delete tests/utils/config-helpers.performance.test.ts
- Remove performance-tests job from test.yml
- Remove benchmarks job from quality.yml
- Remove test:performance script from package.json
- Update all workflow dependencies and summaries
- Update documentation to remove performance test references
This commit is contained in:
overtrue
2025-11-01 00:19:09 +08:00
parent 11ec640849
commit 29096d6e38
7 changed files with 9 additions and 489 deletions
+1 -4
View File
@@ -11,11 +11,9 @@
**包含的任务**:
- 🔍 **代码质量检查**: Linting, TypeScript 类型检查
- 🧪 **单元测试**: 多 Node.js 版本测试 (18, 20)
- 🧪 **单元测试**: 多 Node.js 版本测试 (20, 22)
- 🔗 **集成测试**: 完整的功能集成测试
-**性能测试**: 性能基准和压力测试
- 📊 **代码覆盖率**: 生成覆盖率报告并上传到 Codecov
- 🌐 **浏览器兼容性**: Chrome, Firefox, Safari 测试
- 🔒 **安全扫描**: 依赖安全审计和 CodeQL 分析
- 🏗️ **构建测试**: 验证项目可以正常构建
- 📋 **测试总结**: 汇总所有测试结果
@@ -38,7 +36,6 @@
- 📦 **依赖检查**: 过期包和安全漏洞检查
- 🧮 **代码复杂度分析**: 代码质量指标
- 📚 **文档检查**: JSDoc 覆盖率检查
-**性能基准**: 性能基准测试
- 📋 **质量总结**: 综合质量评分
**质量评分标准**:
+1 -71
View File
@@ -339,73 +339,6 @@ jobs:
echo "⚠️ Test documentation is missing." >> $GITHUB_STEP_SUMMARY
fi
# ============================================================================
# 性能基准
# ============================================================================
benchmarks:
name: ⚡ Performance Benchmarks
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout code
uses: actions/checkout@v4
- name: Detect package manager
id: detect-package-manager
run: |
if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT
exit 0
elif [ -f "${{ github.workspace }}/yarn.lock" ]; then
echo "manager=yarn" >> $GITHUB_OUTPUT
echo "command=install" >> $GITHUB_OUTPUT
exit 0
elif [ -f "${{ github.workspace }}/package-lock.json" ]; then
echo "manager=npm" >> $GITHUB_OUTPUT
echo "command=ci" >> $GITHUB_OUTPUT
exit 0
else
echo "Unable to determine package manager"
exit 1
fi
- name: Setup pnpm
if: steps.detect-package-manager.outputs.manager == 'pnpm'
uses: pnpm/action-setup@v4
with:
version: 10.19.0
- name: 📦 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: ${{ steps.detect-package-manager.outputs.manager }}
- name: 📥 Install dependencies
run: |
${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
${{ steps.detect-package-manager.outputs.manager }} add -D vitest jsdom
- name: ⚡ Run performance benchmarks
run: |
echo "## ⚡ Performance Benchmarks" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 运行性能测试并提取结果
if npx vitest run tests/utils/config-helpers.performance.test.ts --reporter=json > perf-results.json 2>/dev/null; then
echo "✅ Performance tests completed successfully!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "See the detailed performance test results in the test artifacts." >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Performance tests encountered issues. Check the logs for details." >> $GITHUB_STEP_SUMMARY
fi
- name: 📊 Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: performance-benchmarks
path: perf-results.json
retention-days: 30
# ============================================================================
# 质量总结
# ============================================================================
@@ -419,7 +352,6 @@ jobs:
dependencies,
complexity,
documentation,
benchmarks,
]
if: always()
@@ -437,19 +369,17 @@ jobs:
echo "| Dependencies | ${{ needs.dependencies.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Code Complexity | ${{ needs.complexity.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Documentation | ${{ needs.documentation.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Performance | ${{ needs.benchmarks.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 计算总体质量分数
passed=0
total=6
total=5
${{ needs.formatting.result == 'success' }} && passed=$((passed + 1))
${{ needs.typescript.result == 'success' }} && passed=$((passed + 1))
${{ needs.dependencies.result == 'success' }} && passed=$((passed + 1))
${{ needs.complexity.result == 'success' }} && passed=$((passed + 1))
${{ needs.documentation.result == 'success' }} && passed=$((passed + 1))
${{ needs.benchmarks.result == 'success' }} && passed=$((passed + 1))
score=$((passed * 100 / total))
+3 -4
View File
@@ -347,10 +347,9 @@ jobs:
echo "" >> CHANGELOG.md
echo "### 🧪 Testing" >> CHANGELOG.md
echo "- ✅ Unit tests: 100% coverage" >> CHANGELOG.md
echo "- ✅ Integration tests: All scenarios covered" >> CHANGELOG.md
echo "- ✅ Performance tests: All benchmarks passed" >> CHANGELOG.md
echo "- ✅ Browser compatibility: Chrome, Firefox, Safari" >> CHANGELOG.md
echo "- ✅ Unit tests: 100% coverage" >> CHANGELOG.md
echo "- ✅ Integration tests: All scenarios covered" >> CHANGELOG.md
echo "- ✅ Browser compatibility: Chrome, Firefox, Safari" >> CHANGELOG.md
echo "" >> CHANGELOG.md
echo "### 📦 Assets" >> CHANGELOG.md
+4 -64
View File
@@ -189,67 +189,6 @@ jobs:
test-results.xml
retention-days: 7
# ============================================================================
# 性能测试
# ============================================================================
performance-tests:
name: ⚡ Performance Tests
runs-on: ubuntu-latest
timeout-minutes: 25
needs: [unit-tests, integration-tests]
steps:
- name: 📥 Checkout code
uses: actions/checkout@v4
- name: Detect package manager
id: detect-package-manager
run: |
if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT
exit 0
elif [ -f "${{ github.workspace }}/yarn.lock" ]; then
echo "manager=yarn" >> $GITHUB_OUTPUT
echo "command=install" >> $GITHUB_OUTPUT
exit 0
elif [ -f "${{ github.workspace }}/package-lock.json" ]; then
echo "manager=npm" >> $GITHUB_OUTPUT
echo "command=ci" >> $GITHUB_OUTPUT
exit 0
else
echo "Unable to determine package manager"
exit 1
fi
- name: Setup pnpm
if: steps.detect-package-manager.outputs.manager == 'pnpm'
uses: pnpm/action-setup@v4
with:
version: 10.19.0
- name: 📦 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: ${{ steps.detect-package-manager.outputs.manager }}
- name: 📥 Install dependencies
run: |
${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
${{ steps.detect-package-manager.outputs.manager }} add -D vitest jsdom @vitest/ui c8
- name: ⚡ Run performance tests
run: npx vitest run tests/utils/config-helpers.performance.test.ts --reporter=verbose
- name: 📊 Upload performance test results
uses: actions/upload-artifact@v4
if: always()
with:
name: performance-test-results
path: |
coverage/
performance-report.json
retention-days: 7
# ============================================================================
# 代码覆盖率
# ============================================================================
@@ -300,6 +239,8 @@ jobs:
- name: 📊 Run tests with coverage
run: npx vitest run tests/utils/config-helpers*.test.ts --coverage --reporter=verbose
env:
CI: true
- name: 📤 Upload coverage to Codecov
uses: codecov/codecov-action@v4
@@ -457,7 +398,7 @@ jobs:
name: 📋 Test Summary
runs-on: ubuntu-latest
needs:
[unit-tests, integration-tests, performance-tests, coverage, build-test]
[unit-tests, integration-tests, coverage, build-test]
if: always()
steps:
@@ -476,7 +417,6 @@ jobs:
echo "|-----------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Unit Tests | ${{ needs.unit-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Integration Tests | ${{ needs.integration-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Performance Tests | ${{ needs.performance-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Coverage | ${{ needs.coverage.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build Test | ${{ needs.build-test.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
@@ -486,7 +426,7 @@ jobs:
echo "- **Workflow**: [\#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
- name: 🎉 Success notification
if: needs.unit-tests.result == 'success' && needs.integration-tests.result == 'success' && needs.coverage.result == 'success'
if: needs.unit-tests.result == 'success' && needs.integration-tests.result == 'success' && needs.coverage.result == 'success' && needs.build-test.result == 'success'
run: |
echo "🎉 All tests passed successfully!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
-8
View File
@@ -376,17 +376,10 @@ Before committing and pushing your changes, ensure all the following checks pass
- Line coverage: > 95%
- ✅ **Integration Tests**: Integration tests pass (if applicable)
```bash
pnpm test:integration
```
- ✅ **Performance Tests**: Performance benchmarks pass (if applicable)
```bash
pnpm test:performance
```
#### Build Verification
- ✅ **Build Success**: Project builds without errors
@@ -447,7 +440,6 @@ All PRs will automatically run the following checks via GitHub Actions:
- **Type Checking**: TypeScript type validation
- **Unit Tests**: Multi-version Node.js testing (20, 22)
- **Integration Tests**: Full functional integration tests
- **Performance Tests**: Performance benchmarks and stress tests
- **Code Coverage**: Coverage report generation and upload
- **Security Scan**: Dependency audit and CodeQL analysis
- **Build Test**: Verify project builds successfully
-1
View File
@@ -16,7 +16,6 @@
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"test:config-helpers": "vitest run tests/utils/config-helpers",
"test:performance": "vitest run tests/utils/config-helpers.performance.test.ts",
"test:integration": "vitest run tests/utils/config-helpers.integration.test.ts",
"test:watch": "vitest --watch"
},
@@ -1,337 +0,0 @@
/**
* @fileoverview config-helpers.ts 模块的性能和压力测试
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
fetchConfigFromServer,
getConfig,
getCurrentBrowserConfig,
saveHostConfig,
validateConfig,
} from '~/utils/config-helpers'
import {
BrowserMock,
createTestConfig,
FetchMock,
measureExecutionTime,
runBatchTest,
TestCleaner,
} from './test-helpers'
// Mock logger
vi.mock('~/utils/logger', () => ({
logger: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
},
}))
describe('config-helpers Performance Tests', () => {
const browserMock = new BrowserMock()
const cleaner = new TestCleaner()
beforeEach(() => {
browserMock.setLocation({ protocol: 'https:', host: 'localhost:3000' })
localStorage.clear()
vi.clearAllMocks()
vi.mocked(fetch).mockReset()
})
afterEach(() => {
cleaner.cleanup()
})
describe('单个函数性能测试', () => {
it('getCurrentBrowserConfig 应该在 1ms 内完成', async () => {
const { time } = await measureExecutionTime(() => getCurrentBrowserConfig())
expect(time).toBeLessThan(1)
})
it('saveHostConfig 应该在 5ms 内完成', async () => {
const { time } = await measureExecutionTime(() => saveHostConfig('https://example.com:9000'))
expect(time).toBeLessThan(5)
})
it('validateConfig 应该在 1ms 内完成', async () => {
const config = createTestConfig()
const { time } = await measureExecutionTime(() => validateConfig(config))
expect(time).toBeLessThan(1)
})
it('fetchConfigFromServer 应该在合理时间内完成', async () => {
FetchMock.mockJsonResponse({ api: { baseURL: 'test' } })
const { time } = await measureExecutionTime(() => fetchConfigFromServer())
// 网络请求应该在 100ms 内完成(mock 环境)
expect(time).toBeLessThan(100)
})
})
describe('批量操作性能测试', () => {
it('应该处理大量的配置获取请求', async () => {
const { results, averageTime, totalTime } = await runBatchTest(() => getCurrentBrowserConfig(), 1000)
expect(results).toHaveLength(1000)
expect(averageTime).toBeLessThan(1) // 平均每次调用小于 1ms
expect(totalTime).toBeLessThan(1000) // 总时间小于 1 秒
// 验证所有结果都是有效的
results.forEach(result => {
expect(result.config).toBeTruthy()
expect(result.source).toBe('browser')
})
})
it('应该处理大量的配置保存操作', async () => {
const hosts = Array.from({ length: 100 }, (_, i) => `https://host${i}.example.com:${9000 + i}`)
const { results, averageTime } = await runBatchTest(() => {
const hostIndex = Math.floor(Math.random() * hosts.length)
const host = hosts[hostIndex]
if (!host) {
throw new Error('Host not found')
}
return saveHostConfig(host)
}, 100)
expect(results).toHaveLength(100)
expect(averageTime).toBeLessThan(10) // 平均每次保存小于 10ms
// 验证所有保存操作都成功
results.forEach(result => {
expect(result.config).toBeTruthy()
expect(result.source).toBe('localStorage')
})
})
it('应该处理大量的配置验证操作', async () => {
const configs = Array.from({ length: 1000 }, (_, i) =>
createTestConfig({
serverHost: `https://host${i}.com`,
api: { baseURL: `https://api${i}.com` },
})
)
const { results, averageTime } = await runBatchTest(() => {
const configIndex = Math.floor(Math.random() * configs.length)
const config = configs[configIndex]
if (!config) {
throw new Error('Config not found')
}
return validateConfig(config)
}, 1000)
expect(results).toHaveLength(1000)
expect(averageTime).toBeLessThan(0.5) // 平均每次验证小于 0.5ms
// 验证所有配置都通过验证
results.forEach(result => {
expect(result.valid).toBe(true)
expect(result.errors).toHaveLength(0)
})
})
})
describe('并发操作测试', () => {
it('应该处理并发的配置获取请求', async () => {
FetchMock.mockJsonResponse({ api: { baseURL: 'concurrent-test' } })
const concurrentRequests = 50
const promises = Array.from({ length: concurrentRequests }, () => getConfig())
const start = performance.now()
const results = await Promise.all(promises)
const totalTime = performance.now() - start
expect(results).toHaveLength(concurrentRequests)
expect(totalTime).toBeLessThan(1000) // 所有并发请求在 1 秒内完成
// 验证所有结果
results.forEach(result => {
expect(result.config).toBeTruthy()
})
})
it('应该处理并发的保存和获取操作', async () => {
const operations = Array.from({ length: 100 }, (_, i) => {
if (i % 2 === 0) {
// 保存操作
return () => saveHostConfig(`https://host${i}.com`)
} else {
// 获取操作
return () => getCurrentBrowserConfig()
}
})
const promises = operations.map(op => op())
const results = await Promise.all(promises)
expect(results).toHaveLength(100)
// 验证结果
results.forEach((result, index) => {
expect(result.config).toBeTruthy()
if (index % 2 === 0) {
expect(result.source).toBe('localStorage')
} else {
expect(result.source).toBe('browser')
}
})
})
})
describe('内存使用测试', () => {
it('应该不会造成内存泄漏', async () => {
// 创建大量配置对象并立即释放
for (let i = 0; i < 10000; i++) {
const config = createTestConfig({
serverHost: `https://host${i}.com`,
api: { baseURL: `https://api${i}.com` },
s3: {
endpoint: `https://s3-${i}.com`,
region: 'us-east-1',
accessKeyId: `key-${i}`,
secretAccessKey: `secret-${i}`,
},
})
// 验证配置
validateConfig(config)
// 每 1000 次强制垃圾回收(如果可用)
if (i % 1000 === 0 && global.gc) {
global.gc()
}
}
// 测试完成,没有抛出内存错误就算成功
expect(true).toBe(true)
})
it('应该处理大型配置对象', async () => {
const largeConfig = createTestConfig({
// 添加大量数据来测试内存处理
s3: {
endpoint: 'https://s3.example.com',
region: 'us-east-1',
accessKeyId: 'x'.repeat(10000), // 10KB 的数据
secretAccessKey: 'y'.repeat(10000), // 10KB 的数据
},
})
const { time } = await measureExecutionTime(() => validateConfig(largeConfig))
expect(time).toBeLessThan(10) // 即使是大型对象也应该快速处理
})
})
describe('网络性能测试', () => {
it('应该正确处理慢速网络响应', async () => {
// Mock 慢速响应
vi.mocked(fetch).mockImplementationOnce(
() =>
new Promise(
resolve =>
setTimeout(
() =>
resolve({
ok: true,
json: () => Promise.resolve({ api: { baseURL: 'slow-response' } }),
} as Response),
500
) // 500ms 延迟
)
)
const { result, time } = await measureExecutionTime(() => fetchConfigFromServer())
expect(time).toBeGreaterThan(500) // 应该反映实际的网络延迟
expect(result.config).toBeTruthy()
})
it('应该正确处理网络超时', async () => {
// Mock 超时
FetchMock.mockTimeout(100) // 使用较短的超时时间进行测试
const { result, time } = await measureExecutionTime(() => fetchConfigFromServer())
expect(time).toBeLessThan(1000) // 应该在 1 秒内返回
expect(result.source).toBe('browser') // 应该回退到浏览器配置
expect(result.error).toContain('Failed to fetch server config')
}, 10000) // 设置测试超时为 10 秒
})
describe('压力测试', () => {
it('应该在高负载下保持稳定', async () => {
const highLoadOperations = []
// 创建混合的高负载操作
for (let i = 0; i < 1000; i++) {
const operation = i % 4
switch (operation) {
case 0:
highLoadOperations.push(() => getCurrentBrowserConfig())
break
case 1:
highLoadOperations.push(() => saveHostConfig(`https://load-test-${i}.com`))
break
case 2:
highLoadOperations.push(() => validateConfig(createTestConfig()))
break
case 3:
FetchMock.mockJsonResponse({ test: i })
highLoadOperations.push(() => fetchConfigFromServer())
break
}
}
const start = performance.now()
const results = await Promise.all(highLoadOperations.map(op => op()))
const totalTime = performance.now() - start
expect(results).toHaveLength(1000)
expect(totalTime).toBeLessThan(5000) // 5 秒内完成所有操作
// 验证没有操作失败
results.forEach(result => {
expect(result).toBeTruthy()
if ('config' in result) {
expect(result.config).toBeTruthy()
}
})
})
it('应该处理极端的并发情况', async () => {
const extremeConcurrency = 200
// 模拟极端并发:同时进行读写操作
const promises = Array.from({ length: extremeConcurrency }, (_, i) => {
if (i % 3 === 0) {
return saveHostConfig(`https://concurrent-${i}.com`)
} else if (i % 3 === 1) {
FetchMock.mockJsonResponse({ concurrent: i })
return fetchConfigFromServer()
} else {
return getCurrentBrowserConfig()
}
})
const results = await Promise.all(promises)
expect(results).toHaveLength(extremeConcurrency)
// 验证所有操作都成功完成
results.forEach(result => {
expect(result.config).toBeTruthy()
})
})
})
})