Skip to content

Load Tests

Load Tests #140

Workflow file for this run

---
concurrency: ci-$ # Only a single workflow can be executed concurrently
name: Load Tests
on: # yamllint disable-line rule:truthy
workflow_dispatch:
inputs:
environment:
description: The environment to run against
type: choice
options: [dev, test] # nightly should not be initiated manually
type:
description: The type of load test to run
type: choice
options: [EOA, ERC20, ERC721, MIXED]
dynamic:
description: Indicates whether the load test should generate dynamic transactions
type: boolean
default: false
vus:
description: The number of Virtual Users
type: string
default: "1"
txs_per_user:
description: The number of transactions per Virtual User
type: string
default: "1"
txpool_timeout:
description: The timeout for waiting for the transaction pool to empty
type: string
default: "10m0s"
wait_txpool:
description: Waits for transaction pool to empty before collecting results
type: boolean
default: false
receipts_timeout:
description: The timeout for waiting for transaction receipts
type: string
default: "30s"
batch_size:
description: Batch size
type: string
default: "1"
notification:
description: Notification
type: boolean
default: true
workflow_call:
inputs:
environment:
description: The environment to run against
type: string
required: true
type:
description: The type of load test to run
type: string
required: true
dynamic:
description: Indicates whether the load test should generate dynamic transactions
type: boolean
required: true
vus:
description: The number of Virtual Users
type: string
required: true
txs_per_user:
description: The number of transactions per Virtual User
type: string
required: true
txpool_timeout:
description: The timeout for waiting for the transaction pool to empty
type: string
required: true
wait_txpool:
description: Waits for transaction pool to empty before collecting results
type: boolean
required: true
receipts_timeout:
description: The timeout for waiting for transaction receipts
type: string
required: true
batch_size:
description: Batch size
type: string
required: true
notification:
description: Notification
type: boolean
required: true
outputs:
load_test_output:
description: Load Test output
value: ${{ jobs.load_test.outputs.test_output_success }}
total_time:
description: Total Time
value: ${{ jobs.load_test.outputs.total_time }}
total_txs:
description: Total Transactions
value: ${{ jobs.load_test.outputs.total_txs }}
total_blocks:
description: Total Blocks
value: ${{ jobs.load_test.outputs.total_blocks }}
avg_txs_per_second:
description: Average Transactions Per Second
value: ${{ jobs.load_test.outputs.avg_txs_per_second }}
max_txs_per_second:
description: Maximum Transactions Per Second
value: ${{ jobs.load_test.outputs.max_txs_per_second }}
total_gas_used:
description: Total Gas Used
value: ${{ jobs.load_test.outputs.total_gas_used }}
avg_gas_per_tx:
description: Average Gas Used Per Transaction
value: ${{ jobs.load_test.outputs.avg_gas_per_tx }}
avg_gas_utilization:
description: Average Gas Utilization
value: ${{ jobs.load_test.outputs.avg_gas_utilization }}
max_gas_utilization:
description: Maximum Gas Utilization
value: ${{ jobs.load_test.outputs.max_gas_utilization }}
txpool_pending:
description: Pending Transactions Count
value: ${{ jobs.txpool_status.outputs.txpool_pending }}
txpool_queued:
description: Queued Transactions Count
value: ${{ jobs.txpool_status.outputs.txpool_queued }}
results_artifact_id:
description: Results Artifact ID
value: ${{ jobs.load_test.outputs.results_artifact_id }}
secrets:
AWS_ROLE_ARN:
required: true
AWS_S3_BLADE_BUCKET:
required: true
AWS_LOADTESTRUNNER_AMI_ID:
required: true
AWS_LOADTESTRUNNER_SUBNET_ID:
required: true
AWS_LOADTESTRUNNER_SG_ID:
required: true
AWS_LOADTESTRUNNER_MNEMONIC:
required: true
PERSONAL_ACCESS_TOKEN:
required: true
SLACK_WEBHOOK_URL:
required: true
permissions:
id-token: write
contents: read
security-events: write
jobs:
check_network:
name: Check if the network is already deployed
runs-on: ubuntu-latest
outputs:
rpc_url: ${{ steps.rpc_url.outputs.url }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-region: ${{ vars.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
- name: Retrieve state file from s3
id: retrieve_state
run: echo "retrieve_state_output=$(aws s3 cp s3://${{ secrets.AWS_S3_BLADE_BUCKET }}/states/${{ inputs.environment }} state.json)" >> $GITHUB_OUTPUT
- name: Set RPC URL
id: rpc_url
if: contains(steps.retrieve_state.outputs.retrieve_state_output, 'download')
run: echo "url=$(cat state.json | jq -r '.outputs.aws_lb_ext_domain.value // empty')" >> $GITHUB_OUTPUT
load_test_runner:
name: Deploy Load Test Runner
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
needs: check_network
if: needs.check_network.outputs.rpc_url != ''
outputs:
load_test_runner_label: ${{ steps.start_load_teste_runner.outputs.label }}
load_test_runner_instance_id: ${{ steps.start_load_teste_runner.outputs.ec2-instance-id }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-region: ${{ vars.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
- name: Start Load Test Runner
id: start_load_teste_runner
uses: Ethernal-Tech/ec2-github-runner@v3.0.0
with:
mode: start
ec2-instance-type: ${{ vars.AWS_INSTANCE_TYPE }}
ec2-image-id: ${{ secrets.AWS_LOADTESTRUNNER_AMI_ID }}
subnet-id: ${{ secrets.AWS_LOADTESTRUNNER_SUBNET_ID }}
security-group-id: ${{ secrets.AWS_LOADTESTRUNNER_SG_ID }}
github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
aws-resource-tags: >
[
{"Key": "Name", "Value": "${{ inputs.environment }}-load-test-runner"}
]
load_test:
name: Run Load Test
runs-on: ${{ needs.load_test_runner.outputs.load_test_runner_label }}
needs: [check_network, load_test_runner]
outputs:
test_output_success: ${{ steps.load_test_results_success.outputs.test_output }}
total_time: ${{ steps.load_test_results.outputs.total_time }}
total_txs: ${{ steps.load_test_results.outputs.total_txs }}
total_blocks: ${{ steps.load_test_results.outputs.total_blocks }}
avg_txs_per_second: ${{ steps.load_test_results.outputs.avg_txs_per_second }}
max_txs_per_second: ${{ steps.load_test_results.outputs.max_txs_per_second }}
total_gas_used: ${{ steps.load_test_results.outputs.total_gas_used }}
avg_gas_per_tx: ${{ steps.load_test_results.outputs.avg_gas_per_tx }}
avg_gas_utilization: ${{ steps.load_test_results.outputs.avg_gas_utilization }}
max_gas_utilization: ${{ steps.load_test_results.outputs.max_gas_utilization }}
results_artifact_id: ${{ steps.artifact-upload.outputs.artifact-id }}
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1
- name: Build Blade
run: make build
env:
GOPATH: /home/ubuntu/go
GOCACHE: /home/ubuntu/.cache/go-build
GOMODCACHE: /home/ubuntu/.cache/go-mod
- name: Start Load Test
id: load_test_results
run: |
./blade load-test --jsonrpc "http://${{ needs.check_network.outputs.rpc_url }}" --mnemonic "${{ secrets.AWS_LOADTESTRUNNER_MNEMONIC }}" --name "results" --type ${{ inputs.type }} ${{ inputs.dynamic == true && '--dynamic' || '' }} --vus ${{ inputs.vus }} --txs-per-user ${{ inputs.txs_per_user }} --batch-size ${{ inputs.batch_size }} --txpool-timeout ${{ inputs.txpool_timeout }} ${{ inputs.wait_txpool == true && '--wait-txpool' || '' }} --receipts-timeout ${{ inputs.receipts_timeout }} --to-json
echo "total_time=$(cat results_${{ inputs.type }}.json | jq -r '.totalTime')" >> $GITHUB_OUTPUT
echo "total_txs=$(cat results_${{ inputs.type }}.json | jq -r '.totalTxs')" >> $GITHUB_OUTPUT
echo "total_blocks=$(cat results_${{ inputs.type }}.json | jq -r '.totalBlocks')" >> $GITHUB_OUTPUT
echo "avg_txs_per_second=$(cat results_${{ inputs.type }}.json | jq -r '.avgTxsPerSecond')" >> $GITHUB_OUTPUT
echo "max_txs_per_second=$(cat results_${{ inputs.type }}.json | jq -r '.maxTxsPerSecond')" >> $GITHUB_OUTPUT
echo "total_gas_used=$(cat results_${{ inputs.type }}.json | jq -r '.totalGasUsed')" >> $GITHUB_OUTPUT
echo "avg_gas_per_tx=$(cat results_${{ inputs.type }}.json | jq -r '.avgGasPerTx')" >> $GITHUB_OUTPUT
echo "avg_gas_utilization=$(cat results_${{ inputs.type }}.json | jq -r '.avgGasUtilization')" >> $GITHUB_OUTPUT
echo "max_gas_utilization=$(cat results_${{ inputs.type }}.json | jq -r '.maxGasUtilization')" >> $GITHUB_OUTPUT
- name: Run tests success
if: success()
id: load_test_results_success
run: echo "test_output=true" >> $GITHUB_OUTPUT
- name: Upload Artifact
uses: actions/upload-artifact@v4.3.0
id: artifact-upload
with:
name: results_${{ inputs.type }}.tar.gz
path: results_${{ inputs.type }}.json
retention-days: 3
txpool_status:
name: Check txpool status after Load Test
runs-on: ubuntu-latest
needs: [check_network, load_test]
outputs:
txpool_pending: ${{ steps.txpool_status_results.outputs.txpool_pending }}
txpool_queued: ${{ steps.txpool_status_results.outputs.txpool_queued }}
steps:
- name: Get txpool status
id: txpool_status_results
run: |
txpool_status=$(curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"txpool_status","params":[],"id":1}' http://${{ needs.check_network.outputs.rpc_url }} | jq -r .result)
echo "txpool_pending=$(echo $txpool_status | jq -r '.pending')" >> $GITHUB_OUTPUT
echo "txpool_queued=$(echo $txpool_status | jq -r '.queued')" >> $GITHUB_OUTPUT
notification:
name: Load Test Notification
needs: [load_test, txpool_status]
uses: ./.github/workflows/notification-load-test.yml
if: (always() && inputs.notification && needs.load_test.outputs.test_output_success == 'true')
with:
environment: ${{ inputs.environment }}
type: ${{ inputs.type }}
dynamic: ${{ inputs.dynamic }}
vus: ${{ inputs.vus }}
txs_per_user: ${{ inputs.txs_per_user }}
txpool_timeout: ${{ inputs.txpool_timeout }}
wait_txpool: ${{ inputs.wait_txpool }}
receipts_timeout: ${{ inputs.receipts_timeout }}
batch_size: ${{ inputs.batch_size }}
total_time: ${{ needs.load_test.outputs.total_time }}
total_txs: ${{ needs.load_test.outputs.total_txs }}
total_blocks: ${{ needs.load_test.outputs.total_blocks }}
avg_txs_per_second: ${{ needs.load_test.outputs.avg_txs_per_second }}
max_txs_per_second: ${{ needs.load_test.outputs.max_txs_per_second }}
total_gas_used: ${{ needs.load_test.outputs.total_gas_used }}
avg_gas_per_tx: ${{ needs.load_test.outputs.avg_gas_per_tx }}
avg_gas_utilization: ${{ needs.load_test.outputs.avg_gas_utilization }}
max_gas_utilization: ${{ needs.load_test.outputs.max_gas_utilization }}
txpool_pending: ${{ needs.txpool_status.outputs.txpool_pending }}
txpool_queued: ${{ needs.txpool_status.outputs.txpool_queued }}
results_artifact_id: ${{ needs.load_test.outputs.results_artifact_id }}
secrets:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
destroy_load_test_runner:
name: Destroy Load Test Runner
environment: ${{ inputs.environment }}
needs: [load_test_runner, load_test, txpool_status]
if: always()
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4.0.1
with:
aws-region: ${{ vars.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
- name: Stop Load Test Runner
uses: Ethernal-Tech/ec2-github-runner@v3.0.0
with:
mode: stop
label: ${{ needs.load_test_runner.outputs.load_test_runner_label }}
ec2-instance-id: ${{ needs.load_test_runner.outputs.load_test_runner_instance_id }}
github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}