mirror of
https://github.com/stakater/Reloader.git
synced 2026-02-14 18:09:50 +00:00
268 lines
8.8 KiB
YAML
268 lines
8.8 KiB
YAML
name: 'Reloader Load Test'
|
|
description: 'Run Reloader load tests with A/B comparison support'
|
|
|
|
inputs:
|
|
old-ref:
|
|
description: 'Git ref for "old" version (optional, enables A/B comparison)'
|
|
required: false
|
|
default: ''
|
|
new-ref:
|
|
description: 'Git ref for "new" version (defaults to current checkout)'
|
|
required: false
|
|
default: ''
|
|
old-image:
|
|
description: 'Pre-built container image for "old" version (alternative to old-ref)'
|
|
required: false
|
|
default: ''
|
|
new-image:
|
|
description: 'Pre-built container image for "new" version (alternative to new-ref)'
|
|
required: false
|
|
default: ''
|
|
scenarios:
|
|
description: 'Scenarios to run: S1,S4,S6 or all'
|
|
required: false
|
|
default: 'S1,S4,S6'
|
|
test-type:
|
|
description: 'Test type label for summary: quick or full'
|
|
required: false
|
|
default: 'quick'
|
|
duration:
|
|
description: 'Test duration in seconds'
|
|
required: false
|
|
default: '60'
|
|
kind-cluster:
|
|
description: 'Name of existing Kind cluster (if empty, creates new one)'
|
|
required: false
|
|
default: ''
|
|
post-comment:
|
|
description: 'Post results as PR comment'
|
|
required: false
|
|
default: 'false'
|
|
pr-number:
|
|
description: 'PR number for commenting (required if post-comment is true)'
|
|
required: false
|
|
default: ''
|
|
github-token:
|
|
description: 'GitHub token for posting comments'
|
|
required: false
|
|
default: ${{ github.token }}
|
|
comment-header:
|
|
description: 'Optional header text for the comment'
|
|
required: false
|
|
default: ''
|
|
|
|
outputs:
|
|
status:
|
|
description: 'Overall test status: pass or fail'
|
|
value: ${{ steps.run.outputs.status }}
|
|
summary:
|
|
description: 'Markdown summary of results'
|
|
value: ${{ steps.summary.outputs.summary }}
|
|
pass-count:
|
|
description: 'Number of passed scenarios'
|
|
value: ${{ steps.summary.outputs.pass_count }}
|
|
fail-count:
|
|
description: 'Number of failed scenarios'
|
|
value: ${{ steps.summary.outputs.fail_count }}
|
|
|
|
runs:
|
|
using: 'composite'
|
|
steps:
|
|
- name: Determine images to use
|
|
id: images
|
|
shell: bash
|
|
run: |
|
|
# Determine old image
|
|
if [ -n "${{ inputs.old-image }}" ]; then
|
|
echo "old=${{ inputs.old-image }}" >> $GITHUB_OUTPUT
|
|
elif [ -n "${{ inputs.old-ref }}" ]; then
|
|
echo "old=localhost/reloader:old" >> $GITHUB_OUTPUT
|
|
echo "build_old=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "old=" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
# Determine new image
|
|
if [ -n "${{ inputs.new-image }}" ]; then
|
|
echo "new=${{ inputs.new-image }}" >> $GITHUB_OUTPUT
|
|
elif [ -n "${{ inputs.new-ref }}" ]; then
|
|
echo "new=localhost/reloader:new" >> $GITHUB_OUTPUT
|
|
echo "build_new=true" >> $GITHUB_OUTPUT
|
|
else
|
|
# Default: build from current checkout
|
|
echo "new=localhost/reloader:new" >> $GITHUB_OUTPUT
|
|
echo "build_new_current=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Build old image from ref
|
|
if: steps.images.outputs.build_old == 'true'
|
|
shell: bash
|
|
run: |
|
|
CURRENT_SHA=$(git rev-parse HEAD)
|
|
git checkout ${{ inputs.old-ref }}
|
|
docker build -t localhost/reloader:old .
|
|
echo "Built old image from ref: ${{ inputs.old-ref }}"
|
|
git checkout $CURRENT_SHA
|
|
|
|
- name: Build new image from ref
|
|
if: steps.images.outputs.build_new == 'true'
|
|
shell: bash
|
|
run: |
|
|
CURRENT_SHA=$(git rev-parse HEAD)
|
|
git checkout ${{ inputs.new-ref }}
|
|
docker build -t localhost/reloader:new .
|
|
echo "Built new image from ref: ${{ inputs.new-ref }}"
|
|
git checkout $CURRENT_SHA
|
|
|
|
- name: Build new image from current checkout
|
|
if: steps.images.outputs.build_new_current == 'true'
|
|
shell: bash
|
|
run: |
|
|
docker build -t localhost/reloader:new .
|
|
echo "Built new image from current checkout"
|
|
|
|
- name: Build loadtest binary
|
|
shell: bash
|
|
run: |
|
|
cd ${{ github.workspace }}/test/loadtest
|
|
go build -o loadtest ./cmd/loadtest
|
|
|
|
- name: Determine cluster name
|
|
id: cluster
|
|
shell: bash
|
|
run: |
|
|
if [ -n "${{ inputs.kind-cluster }}" ]; then
|
|
echo "name=${{ inputs.kind-cluster }}" >> $GITHUB_OUTPUT
|
|
echo "skip=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "name=reloader-loadtest" >> $GITHUB_OUTPUT
|
|
echo "skip=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Load images into Kind
|
|
shell: bash
|
|
run: |
|
|
CLUSTER="${{ steps.cluster.outputs.name }}"
|
|
|
|
if [ -n "${{ steps.images.outputs.old }}" ]; then
|
|
echo "Loading old image: ${{ steps.images.outputs.old }}"
|
|
kind load docker-image "${{ steps.images.outputs.old }}" --name "$CLUSTER" || true
|
|
fi
|
|
|
|
echo "Loading new image: ${{ steps.images.outputs.new }}"
|
|
kind load docker-image "${{ steps.images.outputs.new }}" --name "$CLUSTER" || true
|
|
|
|
- name: Run load tests
|
|
id: run
|
|
shell: bash
|
|
run: |
|
|
cd ${{ github.workspace }}/test/loadtest
|
|
|
|
ARGS="--new-image=${{ steps.images.outputs.new }}"
|
|
ARGS="$ARGS --scenario=${{ inputs.scenarios }}"
|
|
ARGS="$ARGS --duration=${{ inputs.duration }}"
|
|
ARGS="$ARGS --cluster-name=${{ steps.cluster.outputs.name }}"
|
|
ARGS="$ARGS --skip-image-load"
|
|
|
|
if [ -n "${{ steps.images.outputs.old }}" ]; then
|
|
ARGS="$ARGS --old-image=${{ steps.images.outputs.old }}"
|
|
fi
|
|
|
|
if [ "${{ steps.cluster.outputs.skip }}" = "true" ]; then
|
|
ARGS="$ARGS --skip-cluster"
|
|
fi
|
|
|
|
echo "Running: ./loadtest run $ARGS"
|
|
if ./loadtest run $ARGS; then
|
|
echo "status=pass" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "status=fail" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Generate summary
|
|
id: summary
|
|
shell: bash
|
|
run: |
|
|
cd ${{ github.workspace }}/test/loadtest
|
|
|
|
# Generate markdown summary
|
|
./loadtest summary \
|
|
--results-dir=./results \
|
|
--test-type=${{ inputs.test-type }} \
|
|
--format=markdown > summary.md 2>/dev/null || true
|
|
|
|
# Output to GitHub Step Summary
|
|
cat summary.md >> $GITHUB_STEP_SUMMARY
|
|
|
|
# Store summary for output (using heredoc for multiline)
|
|
{
|
|
echo 'summary<<EOF'
|
|
cat summary.md
|
|
echo 'EOF'
|
|
} >> $GITHUB_OUTPUT
|
|
|
|
# Get pass/fail counts from JSON
|
|
COUNTS=$(./loadtest summary --format=json 2>/dev/null | head -20 || echo '{}')
|
|
echo "pass_count=$(echo "$COUNTS" | grep -o '"pass_count": [0-9]*' | grep -o '[0-9]*' || echo 0)" >> $GITHUB_OUTPUT
|
|
echo "fail_count=$(echo "$COUNTS" | grep -o '"fail_count": [0-9]*' | grep -o '[0-9]*' || echo 0)" >> $GITHUB_OUTPUT
|
|
|
|
- name: Post PR comment
|
|
if: inputs.post-comment == 'true' && inputs.pr-number != ''
|
|
continue-on-error: true
|
|
uses: actions/github-script@v7
|
|
with:
|
|
github-token: ${{ inputs.github-token }}
|
|
script: |
|
|
const fs = require('fs');
|
|
const summaryPath = '${{ github.workspace }}/test/loadtest/summary.md';
|
|
let summary = 'No results available';
|
|
try {
|
|
summary = fs.readFileSync(summaryPath, 'utf8');
|
|
} catch (e) {
|
|
console.log('Could not read summary file:', e.message);
|
|
}
|
|
|
|
const header = '${{ inputs.comment-header }}';
|
|
const status = '${{ steps.run.outputs.status }}';
|
|
const statusEmoji = status === 'pass' ? ':white_check_mark:' : ':x:';
|
|
|
|
const body = [
|
|
header ? header : `## ${statusEmoji} Load Test Results (${{ inputs.test-type }})`,
|
|
'',
|
|
summary,
|
|
'',
|
|
'---',
|
|
`**Artifacts:** [Download](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`,
|
|
].join('\n');
|
|
|
|
try {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: ${{ inputs.pr-number }},
|
|
body: body
|
|
});
|
|
console.log('Comment posted successfully');
|
|
} catch (error) {
|
|
if (error.status === 403) {
|
|
console.log('Could not post comment (fork PR with restricted permissions). Use /loadtest command to run with comment posting.');
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
- name: Upload results
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: loadtest-${{ inputs.test-type }}-results
|
|
path: |
|
|
${{ github.workspace }}/test/loadtest/results/
|
|
retention-days: 30
|
|
|
|
- name: Cleanup Kind cluster (only if we created it)
|
|
if: always() && steps.cluster.outputs.skip == 'false'
|
|
shell: bash
|
|
run: |
|
|
kind delete cluster --name ${{ steps.cluster.outputs.name }} || true
|