mirror of
https://github.com/alibaba/higress.git
synced 2026-02-23 04:00:51 +08:00
427 lines
17 KiB
YAML
427 lines
17 KiB
YAML
name: Wasm Plugin Unit Tests(GO)
|
||
|
||
on:
|
||
push:
|
||
branches: [ main ]
|
||
paths:
|
||
- 'plugins/wasm-go/extensions/**'
|
||
- '.github/workflows/wasm-plugin-unit-test.yml'
|
||
- 'go.mod'
|
||
- 'go.sum'
|
||
pull_request:
|
||
branches: [ "*" ]
|
||
paths:
|
||
- 'plugins/wasm-go/extensions/**'
|
||
- '.github/workflows/wasm-plugin-unit-test.yml'
|
||
- 'go.mod'
|
||
- 'go.sum'
|
||
|
||
env:
|
||
GO111MODULE: on
|
||
CGO_ENABLED: 0
|
||
GOOS: linux
|
||
GOARCH: amd64
|
||
|
||
jobs:
|
||
detect-changed-plugins:
|
||
name: Detect Changed Plugins
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
changed-plugins: ${{ steps.detect.outputs.plugins }}
|
||
has-changes: ${{ steps.detect.outputs.has-changes }}
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0 # 获取完整历史用于比较
|
||
|
||
- name: Detect changed plugins
|
||
id: detect
|
||
run: |
|
||
# 获取变更的文件列表
|
||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||
# PR模式:比较目标分支和源分支
|
||
git fetch origin ${{ github.base_ref }}
|
||
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
|
||
else
|
||
# Push模式:比较当前提交和上一个提交
|
||
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD)
|
||
fi
|
||
|
||
echo "Changed files:"
|
||
echo "$CHANGED_FILES"
|
||
|
||
# 提取变更的插件名称
|
||
CHANGED_PLUGINS=""
|
||
for file in $CHANGED_FILES; do
|
||
if [[ $file =~ ^plugins/wasm-go/extensions/([^/]+)/ ]]; then
|
||
PLUGIN_NAME="${BASH_REMATCH[1]}"
|
||
if [[ ! " $CHANGED_PLUGINS " =~ " $PLUGIN_NAME " ]]; then
|
||
# 修复:只在非空时添加空格
|
||
if [ -z "$CHANGED_PLUGINS" ]; then
|
||
CHANGED_PLUGINS="$PLUGIN_NAME"
|
||
else
|
||
CHANGED_PLUGINS="$CHANGED_PLUGINS $PLUGIN_NAME"
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# 如果没有插件变更,不触发测试
|
||
if [ -z "$CHANGED_PLUGINS" ]; then
|
||
echo "No plugin changes detected, skipping tests"
|
||
echo "has-changes=false" >> $GITHUB_OUTPUT
|
||
echo "plugins=[]" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "Changed plugins: $CHANGED_PLUGINS"
|
||
echo "has-changes=true" >> $GITHUB_OUTPUT
|
||
# 将空格分隔转换为 JSON 数组格式
|
||
PLUGINS_JSON=$(echo "$CHANGED_PLUGINS" | sed 's/ /","/g' | sed 's/^/["/' | sed 's/$/"]/')
|
||
echo "PLUGINS_JSON: $PLUGINS_JSON"
|
||
echo "plugins=$PLUGINS_JSON" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
test:
|
||
name: Test Changed Plugins
|
||
runs-on: ubuntu-latest
|
||
needs: detect-changed-plugins
|
||
if: needs.detect-changed-plugins.outputs.has-changes == 'true'
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
plugin: ${{ fromJSON(needs.detect-changed-plugins.outputs.changed-plugins) }}
|
||
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Set up Go 1.24
|
||
uses: actions/setup-go@v4
|
||
with:
|
||
go-version: 1.24
|
||
cache: true
|
||
|
||
- name: Install test tools
|
||
run: |
|
||
go install gotest.tools/gotestsum@latest
|
||
# 移除gocov工具,直接使用Codecov
|
||
|
||
- name: Build WASM for ${{ matrix.plugin }}
|
||
working-directory: plugins/wasm-go/extensions/${{ matrix.plugin }}
|
||
run: |
|
||
echo "Building WASM for ${{ matrix.plugin }}..."
|
||
|
||
# 检查是否存在main.go文件
|
||
|
||
export GOOS=wasip1
|
||
export GOARCH=wasm
|
||
|
||
# 构建WASM文件,失败时直接退出
|
||
if ! go build -buildmode=c-shared -o main.wasm ./; then
|
||
echo "❌ WASM build failed for ${{ matrix.plugin }}"
|
||
exit 1
|
||
fi
|
||
|
||
# 验证WASM文件是否生成
|
||
if [ ! -f "main.wasm" ]; then
|
||
echo "❌ WASM file not generated for ${{ matrix.plugin }}"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ WASM build successful for ${{ matrix.plugin }}"
|
||
|
||
|
||
- name: Set WASM_PATH environment variable
|
||
run: |
|
||
echo "WASM_PATH=$(pwd)/plugins/wasm-go/extensions/${{ matrix.plugin }}/main.wasm" >> $GITHUB_ENV
|
||
|
||
- name: Run tests with coverage for ${{ matrix.plugin }}
|
||
working-directory: plugins/wasm-go/extensions/${{ matrix.plugin }}
|
||
run: |
|
||
# 检查是否存在main_test.go文件
|
||
if [ -f "main_test.go" ]; then
|
||
echo "Running tests for ${{ matrix.plugin }}..."
|
||
|
||
# 运行测试并生成覆盖率报告
|
||
gotestsum --junitfile ../../../../test-results-${{ matrix.plugin }}.xml \
|
||
--format standard-verbose \
|
||
--jsonfile ../../../../test-output-${{ matrix.plugin }}.json \
|
||
-- -coverprofile=coverage-${{ matrix.plugin }}.out -covermode=atomic -coverpkg=./... ./...
|
||
|
||
echo "✅ Tests completed for ${{ matrix.plugin }}"
|
||
else
|
||
echo "No tests found for ${{ matrix.plugin }}, skipping..."
|
||
# 创建空的测试结果文件
|
||
echo '<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="no-tests" tests="0" failures="0" errors="0" time="0"></testsuite></testsuites>' > ../../../../test-results-${{ matrix.plugin }}.xml
|
||
fi
|
||
|
||
- name: Upload test results for ${{ matrix.plugin }}
|
||
uses: actions/upload-artifact@v4
|
||
if: always()
|
||
with:
|
||
name: test-results-${{ matrix.plugin }}
|
||
path: |
|
||
test-results-${{ matrix.plugin }}.xml
|
||
test-output-${{ matrix.plugin }}.json
|
||
retention-days: 30
|
||
|
||
- name: Upload coverage report for ${{ matrix.plugin }}
|
||
uses: actions/upload-artifact@v4
|
||
if: always()
|
||
with:
|
||
name: coverage-${{ matrix.plugin }}
|
||
path: plugins/wasm-go/extensions/${{ matrix.plugin }}/coverage-${{ matrix.plugin }}.out
|
||
retention-days: 30
|
||
|
||
- name: Upload coverage to Codecov for ${{ matrix.plugin }}
|
||
uses: codecov/codecov-action@v4
|
||
if: always()
|
||
env:
|
||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||
with:
|
||
file: plugins/wasm-go/extensions/${{ matrix.plugin }}/coverage-${{ matrix.plugin }}.out
|
||
flags: wasm-go-plugin-${{ matrix.plugin }}
|
||
name: codecov-${{ matrix.plugin }}
|
||
fail_ci_if_error: false
|
||
verbose: true
|
||
|
||
test-summary:
|
||
name: Test Summary & Coverage
|
||
runs-on: ubuntu-latest
|
||
needs: [detect-changed-plugins, test]
|
||
if: always() && needs.detect-changed-plugins.outputs.has-changes == 'true'
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Set up Go 1.24
|
||
uses: actions/setup-go@v4
|
||
with:
|
||
go-version: 1.24
|
||
cache: true
|
||
|
||
- name: Install required tools
|
||
run: |
|
||
go install github.com/wadey/gocovmerge@latest
|
||
sudo apt-get update && sudo apt-get install -y bc
|
||
|
||
- name: Download all test results
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
pattern: test-results-*
|
||
merge-multiple: true
|
||
path: ${{ github.workspace }}
|
||
|
||
- name: Download all coverage files
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
pattern: coverage-*
|
||
merge-multiple: true
|
||
path: ${{ github.workspace }}
|
||
|
||
|
||
|
||
- name: Generate comprehensive test summary
|
||
run: |
|
||
echo "## 🧪 Go Plugin Test Results" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
total_plugins=0
|
||
passed_plugins=0
|
||
failed_plugins=0
|
||
total_tests=0
|
||
total_failures=0
|
||
total_errors=0
|
||
|
||
echo "### 📊 Test Results by Plugin" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
for result_file in test-results-*.xml; do
|
||
if [ -f "$result_file" ]; then
|
||
plugin_name=$(echo "$result_file" | sed 's/test-results-\(.*\)\.xml/\1/')
|
||
total_plugins=$((total_plugins + 1))
|
||
|
||
# 解析XML获取测试结果
|
||
if grep -q '<testsuite' "$result_file"; then
|
||
# 使用grep解析XML属性,更稳定可靠
|
||
tests=$(grep -o 'tests="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0")
|
||
failures=$(grep -o 'failures="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0")
|
||
errors=$(grep -o 'errors="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0")
|
||
time=$(grep -o 'time="[0-9.]*"' "$result_file" | head -1 | grep -o '[0-9.]*' || echo "0")
|
||
|
||
# 确保数值有效,避免bash算术运算错误
|
||
tests=${tests:-0}
|
||
failures=${failures:-0}
|
||
errors=${errors:-0}
|
||
|
||
# 转换为整数进行算术运算
|
||
total_tests=$((total_tests + tests))
|
||
total_failures=$((total_failures + failures))
|
||
total_errors=$((total_errors + errors))
|
||
|
||
if [ "$failures" = "0" ] && [ "$errors" = "0" ]; then
|
||
echo "✅ **$plugin_name**: $tests tests passed in ${time}s" >> $GITHUB_STEP_SUMMARY
|
||
passed_plugins=$((passed_plugins + 1))
|
||
else
|
||
echo "❌ **$plugin_name**: $tests tests, $failures failures, $errors errors in ${time}s" >> $GITHUB_STEP_SUMMARY
|
||
failed_plugins=$((failed_plugins + 1))
|
||
fi
|
||
else
|
||
echo "⚠️ **$plugin_name**: No tests found" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
fi
|
||
done
|
||
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "### 📈 Coverage Report" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 覆盖率门禁检查
|
||
coverage_failed=false
|
||
|
||
# 解析覆盖率文件 - 使用find命令查找覆盖率文件
|
||
coverage_files=$(find ${{ github.workspace }} -name "coverage-*.out")
|
||
|
||
if [ -n "$coverage_files" ]; then
|
||
echo "Found coverage files:"
|
||
echo "$coverage_files"
|
||
fi
|
||
|
||
for coverage_file in $coverage_files; do
|
||
if [ -f "$coverage_file" ]; then
|
||
plugin_name=$(basename "$coverage_file" | sed 's/coverage-\(.*\)\.out/\1/')
|
||
|
||
# 将覆盖率文件复制到对应插件目录,避免go tool cover的模块依赖问题
|
||
echo "Processing coverage file: $coverage_file"
|
||
|
||
# 检查覆盖率文件是否存在且非空
|
||
if [ -s "$coverage_file" ]; then
|
||
# 将覆盖率文件复制到对应插件目录
|
||
plugin_dir="plugins/wasm-go/extensions/$plugin_name"
|
||
if [ -d "$plugin_dir" ]; then
|
||
cp "$coverage_file" "$plugin_dir/"
|
||
cd "$plugin_dir"
|
||
|
||
# 在插件目录中运行go tool cover,使用正确的模块环境
|
||
coverage_stats=$(go tool cover -func="$(basename "$coverage_file")" 2>&1 | tail -1)
|
||
cd - > /dev/null
|
||
|
||
# 清理复制的文件
|
||
rm -f "$plugin_dir/$(basename "$coverage_file")"
|
||
else
|
||
echo "Plugin directory not found: $plugin_dir"
|
||
coverage_stats=""
|
||
fi
|
||
|
||
echo "Coverage stats result: $coverage_stats"
|
||
|
||
if [ -n "$coverage_stats" ] && echo "$coverage_stats" | grep -q "%"; then
|
||
# 提取覆盖率百分比
|
||
coverage_percent=$(echo "$coverage_stats" | grep -o '[0-9.]*%' | head -1 | sed 's/%//')
|
||
|
||
# 确保数值有效
|
||
coverage_percent=${coverage_percent:-0}
|
||
|
||
if (( $(echo "$coverage_percent > 0" | bc -l) )); then
|
||
# 根据覆盖率设置颜色和图标
|
||
if (( $(echo "$coverage_percent >= 80" | bc -l) )); then
|
||
coverage_icon="🟢"
|
||
elif (( $(echo "$coverage_percent >= 30" | bc -l) )); then
|
||
coverage_icon="🟡"
|
||
else
|
||
coverage_icon="🔴"
|
||
coverage_failed=true
|
||
fi
|
||
|
||
echo "$coverage_icon **$plugin_name**: $coverage_percent%" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 检查覆盖率门禁
|
||
if (( $(echo "$coverage_percent < 30" | bc -l) )); then
|
||
echo "❌ **$plugin_name**: Coverage below 30% threshold!" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
else
|
||
echo "⚪ **$plugin_name**: No statements to cover" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
else
|
||
echo "⚪ **$plugin_name**: Coverage data unavailable" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
else
|
||
echo "⚪ **$plugin_name**: Coverage file is empty or invalid" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
fi
|
||
done
|
||
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "📊 **Coverage reports are now available on Codecov**" >> $GITHUB_STEP_SUMMARY
|
||
echo "🔗 **This Commit Coverage**: https://codecov.io/gh/${{ github.repository }}/commit/${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 覆盖率门禁检查
|
||
if [ "$coverage_failed" = true ]; then
|
||
echo "### ❌ Coverage Gate Failed" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "🚫 **Coverage threshold not met**: Some plugins have coverage below 30%" >> $GITHUB_STEP_SUMMARY
|
||
echo "📋 **Please improve test coverage before merging this PR**" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 退出CI失败
|
||
echo "Coverage gate failed - some plugins below 30% threshold"
|
||
exit 1
|
||
else
|
||
echo "### ✅ Coverage Gate Passed" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "🎉 **All plugins meet the 30% coverage threshold**" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
|
||
echo "### 🎯 Summary" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Total plugins**: $total_plugins" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Passed**: $passed_plugins ✅" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Failed**: $failed_plugins ❌" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Total tests**: $total_tests" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Total failures**: $total_failures" >> $GITHUB_STEP_SUMMARY
|
||
echo "- **Total errors**: $total_errors" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 如果有失败,显示详细信息
|
||
if [ $total_failures -gt 0 ] || [ $total_errors -gt 0 ]; then
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "### ❌ Failed Tests Details" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Failed plugins**: $failed_plugins" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Total failures**: $total_failures" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Total errors**: $total_errors" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "📋 **View detailed logs**: [Click here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# 显示每个失败插件的详细信息
|
||
echo "#### 📊 Failed Plugin Details" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
|
||
for result_file in test-results-*.xml; do
|
||
if [ -f "$result_file" ]; then
|
||
plugin_name=$(echo "$result_file" | sed 's/test-results-\(.*\)\.xml/\1/')
|
||
|
||
# 检查是否有失败
|
||
failures=$(grep -o 'failures="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0")
|
||
errors=$(grep -o 'errors="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0")
|
||
|
||
# 确保数值有效
|
||
failures=${failures:-0}
|
||
errors=${errors:-0}
|
||
|
||
if [ "$failures" -gt 0 ] || [ "$errors" -gt 0 ]; then
|
||
echo "**$plugin_name**:" >> $GITHUB_STEP_SUMMARY
|
||
echo "- Failures: $failures" >> $GITHUB_STEP_SUMMARY
|
||
echo "- Errors: $errors" >> $GITHUB_STEP_SUMMARY
|
||
echo "- [View plugin logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
fi
|
||
fi
|
||
done
|
||
fi |