Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions .github/workflows/run-performance-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Performance test workflow to compare a baseline against a candidate DHIS2 version
# You can run the workflow using the GitHub CLI like so
# gh workflow run run-performance-tests.yml \
# --field simulation_class="org.hisp.dhis.test.tracker.EnrollmentsTest" \
# --field dhis2_image_baseline="dhis2/core:2.42.1" \
# --field dhis2_image_candidate="dhis2/core-dev:latest"
#
# To use a specific database version, provide both dump URL and matching image suffix:
# --field dhis2_db_dump_url="https://databases.dhis2.org/sierra-leone/2.42.2/dhis2-db-sierra-leone.sql.gz" \
# --field dhis2_db_image_suffix="sierra-leone-2.42.2"
name: Performance tests
description: Compare performance between baseline and candidate DHIS2 versions
run-name: Performance test comparing ${{ inputs.dhis2_image_baseline }} to ${{ inputs.dhis2_image_candidate }}

on:
workflow_dispatch:
inputs:
simulation_class:
description: 'Fully qualified Gatling simulation class to run (e.g., org.hisp.dhis.test.EnrollmentsTest)'
required: true
type: string
mvn_args:
description: 'Additional maven arguments'
required: false
default: ''
type: string
# Read https://github.com/dhis2/dhis2-core/blob/master/docker/DOCKERHUB.md on how we publish
# DHIS2 Docker images
dhis2_image_baseline:
description: 'Baseline DHIS2 image for comparison'
required: false
default: 'dhis2/core-dev:latest'
type: string
dhis2_image_candidate:
description: 'Candidate DHIS2 image to compare against baseline'
required: true
type: string
dhis2_db_dump_url:
description: 'URL to DHIS2 database dump (optional)'
required: false
type: string
dhis2_db_image_suffix:
description: 'Docker image suffix for the DB image (e.g., sierra-leone-2.42.2). WARNING: Must match the version in dhis2_db_dump_url'
required: false
default: 'sierra-leone-dev'
type: string

jobs:
performance-tests:
runs-on: perf
timeout-minutes: 40
defaults:
run:
working-directory: dhis-2/dhis-test-performance

steps:
- name: Checkout performance tests
uses: actions/checkout@v5
with:
sparse-checkout: |
dhis-2/dhis-test-performance

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'temurin'

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Clean target directory
run: mvn clean

- name: Run performance tests - baseline
run: |
DHIS2_IMAGE="${{ inputs.dhis2_image_baseline }}" \
SIMULATION_CLASS="${{ inputs.simulation_class }}" \
MVN_ARGS="${{ inputs.mvn_args }}" \
DHIS2_DB_DUMP_URL="${{ inputs.dhis2_db_dump_url }}" \
DHIS2_DB_IMAGE_SUFFIX="${{ inputs.dhis2_db_image_suffix }}" \
./run-simulation.sh

- name: Run performance tests - candidate
run: |
DHIS2_IMAGE="${{ inputs.dhis2_image_candidate }}" \
SIMULATION_CLASS="${{ inputs.simulation_class }}" \
MVN_ARGS="${{ inputs.mvn_args }}" \
DHIS2_DB_DUMP_URL="${{ inputs.dhis2_db_dump_url }}" \
DHIS2_DB_IMAGE_SUFFIX="${{ inputs.dhis2_db_image_suffix }}" \
./run-simulation.sh

# In 3.12 https://github.com/gatling/gatling/issues/4596 Gatling started to write the test
# results into a binary format. Gatling OSS does not support exporting that into an
# accessible format for us. The serializer/deserializer are OSS though. Our fork at
# https://github.com/dhis2/gatling/tree/glog-cli uses them to provide a CLI to extract the
# binary simulation.log into a simulation.csv. CLI releases can be downloaded from
# https://github.com/dhis2/gatling/releases. The CLI is installed on the self-hosted runner.
- name: Convert binary simulation.log to simulation.csv
if: always()
run: |
glog --config ./src/test/resources/gatling.conf --scan-subdirs target/gatling

- name: Upload Gatling report
if: always() # reports should always be uploaded as tests can fail due to our performance assertions
uses: actions/upload-artifact@v4
with:
name: gatling-report-${{ github.run_id }}-${{ github.sha }}
path: dhis-2/dhis-test-performance/target/gatling/

- name: Create test result analysis instructions
if: always()
run: |
echo "## 🚀 Performance Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Performance tests completed comparing:" >> $GITHUB_STEP_SUMMARY
echo "* **Baseline**: \`${{ inputs.dhis2_image_baseline }}\`" >> $GITHUB_STEP_SUMMARY
echo "* **Candidate**: \`${{ inputs.dhis2_image_candidate }}\`" >> $GITHUB_STEP_SUMMARY
echo "* **Simulation Class**: \`${{ inputs.simulation_class }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🖥️ Environment" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Tests run on self-hosted runner with the following specifications:" >> $GITHUB_STEP_SUMMARY
echo "* **CPU**: Intel(R) Xeon(R) CPU E3-1275 v6 @ 3.80GHz (8 core)" >> $GITHUB_STEP_SUMMARY
echo "* **Memory**: 64GiB System Memory" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📥 Download Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Use GitHub CLI to download the performance test results:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Download this run's data:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "gh run download ${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Download latest run's data for current branch:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "gh run download \$(gh run list --workflow=\"Performance tests\" --branch=\"\$(git branch --show-current)\" --limit=1 --json databaseId --jq '.[0].databaseId')" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📊 View Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Results are in \`gatling-report-${{ github.run_id }}-${{ github.sha }}/\` with subdirectories:" >> $GITHUB_STEP_SUMMARY
echo "* **\`<simulation-class>-<timestamp>/\`** - one for each test run (baseline has earlier timestamp)" >> $GITHUB_STEP_SUMMARY
echo " * \`index.html\` - Gatling HTML report (open in browser)" >> $GITHUB_STEP_SUMMARY
echo " * \`simulation-run.txt\` - Test run metadata (indicates baseline/candidate)" >> $GITHUB_STEP_SUMMARY
echo " * \`simulation.log\` - Binary test data (response times, etc.)" >> $GITHUB_STEP_SUMMARY
echo " * \`simulation.csv\` - Parsed binary data in CSV format" >> $GITHUB_STEP_SUMMARY

72 changes: 72 additions & 0 deletions dhis-2/dhis-test-performance/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
services:
# https://docs.dhis2.org/en/manage/reference/dhisconf.html
web:
image: "${DHIS2_IMAGE:-dhis2/core-dev:latest}"
mem_limit: 16gb
environment:
JAVA_OPTS:
"-Dlog4j2.configurationFile=/opt/dhis2/log4j2.xml \
-Xmx10000m -Xms10000m"
volumes:
- ./docker/log4j2.xml:/opt/dhis2/log4j2.xml:ro
- ./docker/dhis.conf:/opt/dhis2/dhis.conf:ro
ports:
- "127.0.0.1:8080:8080" # DHIS2
depends_on:
db:
condition: service_healthy

# Healthcheck sidecar is needed for embedded tomcat images (master branch) that don't have
# curl/wget
web-healthcheck:
image: curlimages/curl:latest
network_mode: service:web
command: ["sleep", "infinity"]
depends_on:
- web
restart: unless-stopped
healthcheck:
test: ["CMD", "sh", "-c", "curl --fail --silent http://localhost:8080/api/ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 120s

# https://docs.dhis2.org/en/manage/reference/postgresql.html
# https://www.postgresql.org/docs/16/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-MEMORY
# https://www.cybertec-postgresql.com/en/effective_cache_size-a-practical-example/
# https://github.com/mastodon/mastodon/blob/fb6c22f5c275685aa644d84c003e1d6922e15d40/docker-compose.yml#L8
# https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
db:
build:
context: ./docker
dockerfile: Dockerfile.postgres
args:
POSTGRES_BASE_IMAGE: postgis/postgis:13-3.5
DHIS2_DB_DUMP_URL: "${DHIS2_DB_DUMP_URL:-https://databases.dhis2.org/sierra-leone/dev/dhis2-db-sierra-leone.sql.gz}"
image: dhis2-postgres:13-3.5-${DHIS2_DB_IMAGE_SUFFIX:-sierra-leone-dev}
mem_limit: 16gb
shm_size: 256mb
volumes:
- ./docker/postgresql.conf:/etc/postgresql.conf
environment:
POSTGRES_USER: &postgres_user dhis
POSTGRES_DB: &postgres_db dhis
POSTGRES_PASSWORD: &postgres_password dhis
# https://www.postgresql.org/docs/current/libpq-envars.html
PGUSER: *postgres_user
PGDATABASE: *postgres_db
PGPASSWORD: *postgres_password
healthcheck:
test:
[
"CMD-SHELL",
'psql --quiet --host=127.0.0.1 --port=5432 --set=application_name=docker --command "/** docker healthcheck **/ SELECT ''ok''" > /dev/null',
]
start_period: 120s
interval: 3s
timeout: 3s
retries: 5
ports:
- "127.0.0.1:5432:5432"

18 changes: 18 additions & 0 deletions dhis-2/dhis-test-performance/docker/Dockerfile.postgres
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ARG POSTGRES_BASE_IMAGE=postgis/postgis:13-3.5
ARG DHIS2_DB_DUMP_URL

FROM busybox AS downloader
ARG DHIS2_DB_DUMP_URL
WORKDIR /tmp
RUN wget --output-document dump.sql.gz "$DHIS2_DB_DUMP_URL"

FROM ${POSTGRES_BASE_IMAGE}

ENV POSTGRES_USER=dhis \
POSTGRES_DB=dhis \
POSTGRES_PASSWORD=dhis \
PGUSER=dhis \
PGDATABASE=dhis \
PGPASSWORD=dhis

COPY --from=downloader /tmp/dump.sql.gz /docker-entrypoint-initdb.d/
9 changes: 9 additions & 0 deletions dhis-2/dhis-test-performance/docker/dhis.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
connection.dialect = org.hibernate.dialect.PostgreSQLDialect
connection.driver_class = org.postgresql.Driver
connection.url = jdbc:postgresql://db/dhis
connection.username = dhis
connection.password = dhis

system.update_notifications_enabled = 0ff

tracker.import.preheat.cache.enabled = off
Loading
Loading