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
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
Create a new file in your repository at .github/workflows/performance-test.yml:
name: Performance Testson:push:branches: [ main, develop ]pull_request:branches: [ main ]# Optional: Run on a scheduleschedule:- cron: '0 0 * * 1' # Run at midnight every Mondayjobs:performance-test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: '16'- name: Install LoadFocus JMeter API Clientrun: npm install -g @loadfocus/loadfocus-api-client- name: Configure LoadFocus API Clientrun: |loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}- name: Run Performance Testsrun: |# --name is the exact name of a test you saved in LoadFocusloadfocus-api jmeter run-test \--name "My_JMeter_Test" \--thresholds "avgresponse<=200,errors==0,p95<=250" \--format json > performance_results.json- name: Upload Performance Test Resultsif: always()uses: actions/upload-artifact@v4with:name: performance-test-resultspath: performance_results.json
run-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
To make deployment dependent on performance test results:
name: Build, Test, and Deployon:push:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:# Your build steps...performance-test:needs: buildruns-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: '16'- name: Install LoadFocus JMeter API Clientrun: npm install -g @loadfocus/loadfocus-api-client- name: Configure LoadFocus API Clientrun: |loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}- name: Run Performance Testsrun: |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 Resultsif: always()uses: actions/upload-artifact@v4with:name: performance-test-resultspath: performance_results.jsondeploy:needs: performance-testruns-on: ubuntu-lateststeps:# Your deployment steps...
Advanced Configuration
Matrix Testing for Multiple Environments
Run tests against multiple environments or configurations:
jobs:performance-test:runs-on: ubuntu-lateststrategy:matrix:environment: [dev, staging, production]test-type: [api, frontend]steps:# Setup steps...- name: Run Performance Testsrun: |TEST_NAME="${{ matrix.test-type }}_test_${{ matrix.environment }}"# Adjust thresholds based on environmentif [ "${{ matrix.environment }}" == "production" ]; thenTHRESHOLDS="avgresponse<=150,errors==0,p95<=200"elseTHRESHOLDS="avgresponse<=300,errors==0,p95<=500"filoadfocus-api jmeter run-test \--name "$TEST_NAME" \--thresholds "$THRESHOLDS" \--format json > "performance_results_${{ matrix.environment }}_${{ matrix.test-type }}.json"
Commenting Test Results on PRs
Add performance test results as a comment on pull requests:
- name: Comment PRuses: actions/github-script@v6if: 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
Create a reusable workflow for performance testing:
# .github/workflows/reusable-performance-test.ymlname: Reusable Performance Teston:workflow_call:inputs:test-name:required: truetype: stringthresholds:required: falsetype: stringdefault: "avgresponse<=200,errors==0,p95<=250"wait-timeout:required: falsetype: numberdefault: 1800secrets:LOADFOCUS_API_KEY:required: trueLOADFOCUS_TEAM_ID:required: truejobs:performance-test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: '16'- name: Install LoadFocus JMeter API Clientrun: npm install -g @loadfocus/loadfocus-api-client- name: Configure LoadFocus API Clientrun: |loadfocus-api config set --apikey ${{ secrets.LOADFOCUS_API_KEY }} --teamid ${{ secrets.LOADFOCUS_TEAM_ID }}- name: Run Performance Testsrun: |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 Resultsif: always()uses: actions/upload-artifact@v4with:name: performance-test-resultspath: performance_results.json
Then call it from another workflow:
# .github/workflows/main.ymljobs:call-performance-test:uses: ./.github/workflows/reusable-performance-test.ymlwith: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
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: falseEnvironment-specific Tests: Use GitHub environments for different test configurations:
jobs:performance-test:runs-on: ubuntu-latestenvironment: staging# Environment-specific variables are available hereConditional 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.