GitHub Actions
This guide shows how to start a LoadFocus JMeter test from a GitHub Actions workflow, wait for it to finish and fail the workflow when a threshold is missed. It uses the LoadFocus API Client (loadfocus-api, installed from npm). Create and save the test in LoadFocus first, see How to run a new JMeter load test; the workflow starts that saved test by name.
Setup Steps
Section titled “Setup Steps”1. Store Credentials as GitHub Secrets
Section titled “1. Store Credentials as GitHub Secrets”First, store your LoadFocus API credentials as GitHub repository secrets:
-
Go to your GitHub repository
-
Navigate to Settings > Secrets and variables > Actions
-
Add the following repository secrets:
LOADFOCUS_API_KEY: Your LoadFocus API keyLOADFOCUS_TEAM_ID: Your LoadFocus team ID
Both are on the API Keys page of your LoadFocus account settings.
2. Create a GitHub Actions Workflow
Section titled “2. Create a GitHub Actions Workflow”Create a new file in your repository at .github/workflows/performance-test.yml:
name: Performance Tests
on: push: branches: [ main, develop ] pull_request: branches: [ main ] # Optional: Run on a schedule schedule: - cron: '0 0 * * 1' # Run at midnight every Monday
jobs: performance-test: runs-on: ubuntu-latest
steps: - uses: actions/checkout@v3
- name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '16'
- name: Install LoadFocus JMeter API Client run: npm install -g @loadfocus/loadfocus-api-client
- name: Configure LoadFocus API Client run: | loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}
- name: Run Performance Tests run: | # --name is the exact name of a test you saved in LoadFocus loadfocus-api jmeter run-test \ --name "My_JMeter_Test" \ --thresholds "avgresponse<=200,errors==0,p95<=250" \ --format json > performance_results.json
- name: Upload Performance Test Results if: always() uses: actions/upload-artifact@v4 with: name: performance-test-results path: performance_results.jsonrun-test starts the saved test, waits for it to finish and checks the thresholds. If any threshold is missed, or the run fails, the command exits with code 1 and the step fails. Thresholds are checked for every request label separately, so one slow request is enough to fail the run. errors is a count of failed requests, not a percentage. In the examples below, replace the test names with the exact name of your saved test.
The output file starts with a few progress lines before the JSON object. To get a clean JSON file, keep only the lines from the first line that is just {: sed -n '/^{$/,$p' performance_results.json > results.json.
3. Add Performance Testing to Your Deployment Workflow
Section titled “3. Add Performance Testing to Your Deployment Workflow”To make deployment dependent on performance test results:
name: Build, Test, and Deploy
on: push: branches: [ main ]
jobs: build: runs-on: ubuntu-latest steps: # Your build steps...
performance-test: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '16'
- name: Install LoadFocus JMeter API Client run: npm install -g @loadfocus/loadfocus-api-client
- name: Configure LoadFocus API Client run: | loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}
- name: Run Performance Tests run: | loadfocus-api jmeter run-test \ --name "My_JMeter_Test" \ --thresholds "avgresponse<=200,errors==0,p95<=250" \ --format json > performance_results.json
- name: Upload Performance Test Results if: always() uses: actions/upload-artifact@v4 with: name: performance-test-results path: performance_results.json
deploy: needs: performance-test runs-on: ubuntu-latest steps: # Your deployment steps...Advanced Configuration
Section titled “Advanced Configuration”Matrix Testing for Multiple Environments
Section titled “Matrix Testing for Multiple Environments”Run tests against multiple environments or configurations:
jobs: performance-test: runs-on: ubuntu-latest strategy: matrix: environment: [dev, staging, production] test-type: [api, frontend]
steps: # Setup steps...
- name: Run Performance Tests run: | TEST_NAME="${{ matrix.test-type }}_test_${{ matrix.environment }}"
# Adjust thresholds based on environment if [ "${{ matrix.environment }}" == "production" ]; then THRESHOLDS="avgresponse<=150,errors==0,p95<=200" else THRESHOLDS="avgresponse<=300,errors==0,p95<=500" fi
loadfocus-api jmeter run-test \ --name "$TEST_NAME" \ --thresholds "$THRESHOLDS" \ --format json > "performance_results_${{ matrix.environment }}_${{ matrix.test-type }}.json"Commenting Test Results on PRs
Section titled “Commenting Test Results on PRs”Add performance test results as a comment on pull requests:
- name: Comment PR uses: actions/github-script@v6 if: always() && github.event_name == 'pull_request' with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); const raw = fs.readFileSync('performance_results.json', 'utf8'); // the file starts with progress lines; the JSON begins at the first line that is only { const results = JSON.parse(raw.slice(raw.search(/^\{$/m)));
let comment = '## Performance Test Results\n\n'; comment += `**Overall Result:** ${results.overallResult}\n\n`;
comment += '### Results by Label\n\n'; for (const label of results.labels) { comment += `#### ${label.label}\n`; comment += `- **Result:** ${label.result}\n`; comment += `- **Samples:** ${label.metrics.samples}\n`; comment += `- **Avg Response:** ${label.metrics.avgresponse}ms\n`; comment += `- **Error Rate:** ${label.metrics.errors}\n\n`; }
github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: comment });Reusable Workflow
Section titled “Reusable Workflow”Create a reusable workflow for performance testing:
name: Reusable Performance Test
on: workflow_call: inputs: test-name: required: true type: string thresholds: required: false type: string default: "avgresponse<=200,errors==0,p95<=250" wait-timeout: required: false type: number default: 1800 secrets: LOADFOCUS_API_KEY: required: true LOADFOCUS_TEAM_ID: required: true
jobs: performance-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '16'
- name: Install LoadFocus JMeter API Client run: npm install -g @loadfocus/loadfocus-api-client
- name: Configure LoadFocus API Client run: | loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}
- name: Run Performance Tests run: | loadfocus-api jmeter run-test \ --name "${{ inputs.test-name }}" \ --thresholds "${{ inputs.thresholds }}" \ --wait-timeout ${{ inputs.wait-timeout }} \ --format json > performance_results.json
- name: Upload Performance Test Results if: always() uses: actions/upload-artifact@v4 with: name: performance-test-results path: performance_results.jsonThen call it from another workflow:
jobs: call-performance-test: uses: ./.github/workflows/reusable-performance-test.yml with: test-name: "API_Performance_Test" thresholds: "avgresponse<=150,errors==0" secrets: LOADFOCUS_API_KEY: ${{ secrets.LOADFOCUS_API_KEY }} LOADFOCUS_TEAM_ID: ${{ secrets.LOADFOCUS_TEAM_ID }}Tips for GitHub Actions Integration
Section titled “Tips for GitHub Actions Integration”-
Caching: Cache npm dependencies to speed up workflow runs:
- name: Cache Node modulesuses: actions/cache@v3with:path: ~/.npmkey: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}restore-keys: |${{ runner.os }}-node- -
Concurrency Control: Limit concurrent performance tests:
concurrency:group: performance-test-${{ github.ref }}cancel-in-progress: false -
Environment-specific Tests: Use GitHub environments for different test configurations:
jobs:performance-test:runs-on: ubuntu-latestenvironment: staging# Environment-specific variables are available here -
Conditional Testing: Only run performance tests when specific files change:
jobs:performance-test:if: |contains(github.event.pull_request.labels.*.name, 'performance-test') ||github.event_name == 'schedule' ||contains(github.event.head_commit.message, '[perf-test]')
For more information, refer to the GitHub Actions documentation and the LoadFocus API Client documentation.