From 4ce33431cddd6199ca23fad715bd348f44a1b258 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 09:00:31 +0200 Subject: [PATCH 01/16] test: simplify waiting for perf containers --- .../dhis-test-performance/run-simulation.sh | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/dhis-2/dhis-test-performance/run-simulation.sh b/dhis-2/dhis-test-performance/run-simulation.sh index 6d39247d4e92..4d6b438c4e21 100755 --- a/dhis-2/dhis-test-performance/run-simulation.sh +++ b/dhis-2/dhis-test-performance/run-simulation.sh @@ -22,7 +22,6 @@ show_usage() { echo " Options: https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilerOptions.md" echo " MVN_ARGS Additional Maven arguments passed to mvn gatling:test" echo " HEALTHCHECK_TIMEOUT Max wait time for DHIS2 startup in seconds (default: 300)" - echo " HEALTHCHECK_INTERVAL Check interval for DHIS2 startup in seconds (default: 10)" echo "" echo "EXAMPLES:" echo " # Basic test run" @@ -52,7 +51,6 @@ MVN_ARGS=${MVN_ARGS:-""} DHIS2_DB_DUMP_URL=${DHIS2_DB_DUMP_URL:-"https://databases.dhis2.org/sierra-leone/dev/dhis2-db-sierra-leone.sql.gz"} DHIS2_DB_IMAGE_SUFFIX=${DHIS2_DB_IMAGE_SUFFIX:-"sierra-leone-dev"} HEALTHCHECK_TIMEOUT=${HEALTHCHECK_TIMEOUT:-300} # default of 5min -HEALTHCHECK_INTERVAL=${HEALTHCHECK_INTERVAL:-10} # default of 10s PROF_ARGS=${PROF_ARGS:=""} parse_prof_args() { @@ -88,30 +86,20 @@ trap cleanup EXIT INT start_containers() { echo "Testing with image: $DHIS2_IMAGE" + echo "Waiting for containers to be ready..." + + local start_time + start_time=$(date +%s) if [ -n "$PROF_ARGS" ]; then docker compose -f docker-compose.yml -f docker-compose.profile.yml down --volumes - docker compose -f docker-compose.yml -f docker-compose.profile.yml up --detach + docker compose -f docker-compose.yml -f docker-compose.profile.yml up --detach --wait --wait-timeout "$HEALTHCHECK_TIMEOUT" else docker compose down --volumes - docker compose up --detach + docker compose up --detach --wait --wait-timeout "$HEALTHCHECK_TIMEOUT" fi -} - -wait_for_health() { - echo "Waiting for DHIS2 to start..." - local start_time - start_time=$(date +%s) - while ! docker compose ps web-healthcheck | grep -q "healthy"; do - sleep "$HEALTHCHECK_INTERVAL" - echo "Still waiting..." - if [ $(($(date +%s) - start_time)) -gt "$HEALTHCHECK_TIMEOUT" ]; then - echo "Timeout waiting for DHIS2 to start" - exit 1 - fi - done - echo "DHIS2 is ready! (took $(($(date +%s) - start_time))s)" + echo "All containers ready! (took $(($(date +%s) - start_time))s)" } save_profiler_data() { @@ -189,7 +177,7 @@ generate_metadata() { echo "Generating run metadata..." { echo "RUN_DIR=$gatling_run_dir" - echo "COMMAND=DHIS2_IMAGE=$DHIS2_IMAGE DHIS2_DB_DUMP_URL=$DHIS2_DB_DUMP_URL SIMULATION_CLASS=$SIMULATION_CLASS${MVN_ARGS:+ MVN_ARGS=$MVN_ARGS}${HEALTHCHECK_TIMEOUT:+ HEALTHCHECK_TIMEOUT=$HEALTHCHECK_TIMEOUT}${HEALTHCHECK_INTERVAL:+ HEALTHCHECK_INTERVAL=$HEALTHCHECK_INTERVAL} $0" + echo "COMMAND=DHIS2_IMAGE=$DHIS2_IMAGE DHIS2_DB_DUMP_URL=$DHIS2_DB_DUMP_URL SIMULATION_CLASS=$SIMULATION_CLASS${MVN_ARGS:+ MVN_ARGS=$MVN_ARGS}${HEALTHCHECK_TIMEOUT:+ HEALTHCHECK_TIMEOUT=$HEALTHCHECK_TIMEOUT} $0" echo "SCRIPT_NAME=$0" echo "SCRIPT_ARGS=$*" echo "DHIS2_IMAGE=$DHIS2_IMAGE" @@ -198,7 +186,6 @@ generate_metadata() { echo "SIMULATION_CLASS=$SIMULATION_CLASS" echo "MVN_ARGS=$MVN_ARGS" echo "HEALTHCHECK_TIMEOUT=$HEALTHCHECK_TIMEOUT" - echo "HEALTHCHECK_INTERVAL=$HEALTHCHECK_INTERVAL" echo "GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')" echo "GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo 'unknown')" echo "GIT_DIRTY=\$([ -n \"\$(git status --porcelain 2>/dev/null)\" ] && echo 'true' || echo 'false')" @@ -206,7 +193,6 @@ generate_metadata() { } start_containers -wait_for_health prepare_database start_profiler run_simulation From 528a42d7045190389ff435c51dbc26f72282aa27 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 09:21:29 +0200 Subject: [PATCH 02/16] test: use bao image for arm support --- dhis-2/dhis-test-performance/docker-compose.yml | 4 ++-- dhis-2/dhis-test-performance/docker/Dockerfile.postgres | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dhis-2/dhis-test-performance/docker-compose.yml b/dhis-2/dhis-test-performance/docker-compose.yml index 125058271238..8b70678a7b0b 100644 --- a/dhis-2/dhis-test-performance/docker-compose.yml +++ b/dhis-2/dhis-test-performance/docker-compose.yml @@ -42,9 +42,9 @@ services: context: ./docker dockerfile: Dockerfile.postgres args: - POSTGRES_BASE_IMAGE: postgis/postgis:13-3.5 + POSTGRES_BASE_IMAGE: ghcr.io/baosystems/postgis:14-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} + image: dhis2-postgres:14-3.5-${DHIS2_DB_IMAGE_SUFFIX:-sierra-leone-dev} mem_limit: 16gb shm_size: 256mb volumes: diff --git a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres index 41b8eb74a9ac..3e35b51b480e 100644 --- a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres +++ b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres @@ -1,4 +1,4 @@ -ARG POSTGRES_BASE_IMAGE=postgis/postgis:13-3.5 +ARG POSTGRES_BASE_IMAGE=ghcr.io/baosystems/postgis:14-3.5 ARG DHIS2_DB_DUMP_URL FROM busybox AS downloader From 7a63fd840f0558aa60bf77e2f5257ef5fe240e83 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 09:31:05 +0200 Subject: [PATCH 03/16] test: get rid of pull warning --- dhis-2/dhis-test-performance/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhis-2/dhis-test-performance/docker-compose.yml b/dhis-2/dhis-test-performance/docker-compose.yml index 8b70678a7b0b..8ea8528c26ba 100644 --- a/dhis-2/dhis-test-performance/docker-compose.yml +++ b/dhis-2/dhis-test-performance/docker-compose.yml @@ -44,7 +44,7 @@ services: args: POSTGRES_BASE_IMAGE: ghcr.io/baosystems/postgis:14-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:14-3.5-${DHIS2_DB_IMAGE_SUFFIX:-sierra-leone-dev} + image: localhost/dhis2-postgres:14-3.5-${DHIS2_DB_IMAGE_SUFFIX:-sierra-leone-dev} mem_limit: 16gb shm_size: 256mb volumes: From 9b771c471676187c3aa7ad78e6af3d895c0b344c Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 10:29:15 +0200 Subject: [PATCH 04/16] test: document reason for Dockerfile.postgres --- dhis-2/dhis-test-performance/docker/Dockerfile.postgres | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres index 3e35b51b480e..9ad8f7d09d12 100644 --- a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres +++ b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres @@ -1,3 +1,5 @@ +# Dockerfile to build the DB dump into the Docker image essentially caching the DB dump using +# Dockers image/layer caching. The dump will be restored on each container creation. ARG POSTGRES_BASE_IMAGE=ghcr.io/baosystems/postgis:14-3.5 ARG DHIS2_DB_DUMP_URL From e435631bfe57369d57966bebb88574ae6d191de5 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 10:38:20 +0200 Subject: [PATCH 05/16] test: fix log4j2.xml and typo --- dhis-2/dhis-test-performance/docker/dhis.conf | 2 +- .../dhis-test-performance/docker/log4j2.xml | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 dhis-2/dhis-test-performance/docker/log4j2.xml diff --git a/dhis-2/dhis-test-performance/docker/dhis.conf b/dhis-2/dhis-test-performance/docker/dhis.conf index 5ba1b1b4930b..127ff0e15dbf 100644 --- a/dhis-2/dhis-test-performance/docker/dhis.conf +++ b/dhis-2/dhis-test-performance/docker/dhis.conf @@ -4,6 +4,6 @@ connection.url = jdbc:postgresql://db/dhis connection.username = dhis connection.password = dhis -system.update_notifications_enabled = 0ff +system.update_notifications_enabled = off tracker.import.preheat.cache.enabled = off diff --git a/dhis-2/dhis-test-performance/docker/log4j2.xml b/dhis-2/dhis-test-performance/docker/log4j2.xml new file mode 100644 index 000000000000..af0629a5ffc3 --- /dev/null +++ b/dhis-2/dhis-test-performance/docker/log4j2.xml @@ -0,0 +1,40 @@ + + + + + %-5level %c [%t] %msg%n + + + + + + + + + + + + + + + + + From bc95d2b8105c2d517060076e2abf0c58516d76a6 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 10:43:29 +0200 Subject: [PATCH 06/16] test: fix postgres.conf location --- dhis-2/dhis-test-performance/docker-compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dhis-2/dhis-test-performance/docker-compose.yml b/dhis-2/dhis-test-performance/docker-compose.yml index 8ea8528c26ba..d1f8fff782c0 100644 --- a/dhis-2/dhis-test-performance/docker-compose.yml +++ b/dhis-2/dhis-test-performance/docker-compose.yml @@ -48,7 +48,8 @@ services: mem_limit: 16gb shm_size: 256mb volumes: - - ./docker/postgresql.conf:/etc/postgresql.conf + - ./docker/postgresql.conf:/etc/postgresql/postgresql.conf:ro + command: postgres -c config_file=/etc/postgresql/postgresql.conf environment: POSTGRES_USER: &postgres_user dhis POSTGRES_DB: &postgres_db dhis From 0aaca52024dd94c821805ed13eda4f55104d4706 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 10:57:21 +0200 Subject: [PATCH 07/16] test: add hard cpu limits --- dhis-2/dhis-test-performance/docker-compose.profile.yml | 2 +- dhis-2/dhis-test-performance/docker-compose.yml | 4 +++- dhis-2/dhis-test-performance/docker/Dockerfile.postgres | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dhis-2/dhis-test-performance/docker-compose.profile.yml b/dhis-2/dhis-test-performance/docker-compose.profile.yml index 122dec642a07..c7e61b6a11e5 100644 --- a/dhis-2/dhis-test-performance/docker-compose.profile.yml +++ b/dhis-2/dhis-test-performance/docker-compose.profile.yml @@ -38,7 +38,7 @@ services: else echo "async-profiler already installed" fi && - chmod 777 /profiler-output + chmod 755 /profiler-output ' volumes: - async-profiler:/usr/local diff --git a/dhis-2/dhis-test-performance/docker-compose.yml b/dhis-2/dhis-test-performance/docker-compose.yml index d1f8fff782c0..6e87fe6e7505 100644 --- a/dhis-2/dhis-test-performance/docker-compose.yml +++ b/dhis-2/dhis-test-performance/docker-compose.yml @@ -2,6 +2,7 @@ services: # https://docs.dhis2.org/en/manage/reference/dhisconf.html web: image: "${DHIS2_IMAGE:-dhis2/core-dev:latest}" + cpus: 4 mem_limit: 16gb environment: JAVA_OPTS: @@ -45,6 +46,7 @@ services: POSTGRES_BASE_IMAGE: ghcr.io/baosystems/postgis:14-3.5 DHIS2_DB_DUMP_URL: "${DHIS2_DB_DUMP_URL:-https://databases.dhis2.org/sierra-leone/dev/dhis2-db-sierra-leone.sql.gz}" image: localhost/dhis2-postgres:14-3.5-${DHIS2_DB_IMAGE_SUFFIX:-sierra-leone-dev} + cpus: 4 mem_limit: 16gb shm_size: 256mb volumes: @@ -65,7 +67,7 @@ services: '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 + interval: 5s timeout: 3s retries: 5 ports: diff --git a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres index 9ad8f7d09d12..063ee0c774d0 100644 --- a/dhis-2/dhis-test-performance/docker/Dockerfile.postgres +++ b/dhis-2/dhis-test-performance/docker/Dockerfile.postgres @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 # Dockerfile to build the DB dump into the Docker image essentially caching the DB dump using # Dockers image/layer caching. The dump will be restored on each container creation. ARG POSTGRES_BASE_IMAGE=ghcr.io/baosystems/postgis:14-3.5 From 510415b80766ce383fd14f90ceeae61867730091 Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 11:24:02 +0200 Subject: [PATCH 08/16] test: allow running specific perf test git tag --- .github/workflows/run-performance-tests.yml | 22 +++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-performance-tests.yml b/.github/workflows/run-performance-tests.yml index 6f2ad7f492b5..0eb1f29f18ed 100644 --- a/.github/workflows/run-performance-tests.yml +++ b/.github/workflows/run-performance-tests.yml @@ -1,11 +1,24 @@ # Performance test workflow to compare a baseline against a candidate DHIS2 version -# You can run the workflow using the GitHub CLI like so +# You can run the workflow using the GitHub CLI like so: +# +# Basic example (required args only): +# gh workflow run run-performance-tests.yml \ +# --field perf_tests_git_ref="master" \ +# --field simulation_class="org.hisp.dhis.test.tracker.TrackerTest" \ +# --field dhis2_image_candidate="dhis2/core-dev:latest" +# +# With custom baseline: # gh workflow run run-performance-tests.yml \ +# --field perf_tests_git_ref="master" \ # --field simulation_class="org.hisp.dhis.test.tracker.TrackerTest" \ # --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: +# With specific database version: +# gh workflow run run-performance-tests.yml \ +# --field perf_tests_git_ref="2.42.2" \ +# --field simulation_class="org.hisp.dhis.test.tracker.TrackerTest" \ +# --field dhis2_image_candidate="dhis2/core:2.42.2" \ # --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 @@ -15,6 +28,10 @@ run-name: Performance test comparing ${{ inputs.dhis2_image_baseline }} to ${{ i on: workflow_dispatch: inputs: + perf_tests_git_ref: + description: 'Git ref (tag/branch/commit) to checkout dhis2-core performance tests' + required: true + type: string simulation_class: description: 'Fully qualified Gatling simulation class to run (e.g., org.hisp.dhis.test.TrackerTest)' required: true @@ -57,6 +74,7 @@ jobs: - name: Checkout performance tests uses: actions/checkout@v5 with: + ref: ${{ inputs.perf_tests_git_ref }} sparse-checkout: | dhis-2/dhis-test-performance From e637daedc7b2f988a46fc2e8e15ea404997529cd Mon Sep 17 00:00:00 2001 From: teleivo Date: Wed, 1 Oct 2025 13:17:01 +0200 Subject: [PATCH 09/16] test: cannot change permission --- dhis-2/dhis-test-performance/docker-compose.profile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhis-2/dhis-test-performance/docker-compose.profile.yml b/dhis-2/dhis-test-performance/docker-compose.profile.yml index c7e61b6a11e5..122dec642a07 100644 --- a/dhis-2/dhis-test-performance/docker-compose.profile.yml +++ b/dhis-2/dhis-test-performance/docker-compose.profile.yml @@ -38,7 +38,7 @@ services: else echo "async-profiler already installed" fi && - chmod 755 /profiler-output + chmod 777 /profiler-output ' volumes: - async-profiler:/usr/local From 1ac3089902e3c31d22a21e3ef0fe21a7075d6ae8 Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 08:26:07 +0200 Subject: [PATCH 10/16] test: login and let Gatling use cookie --- .../src/test/org/hisp/dhis/test/tracker/TrackerTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dhis-2/dhis-test-performance/src/test/org/hisp/dhis/test/tracker/TrackerTest.java b/dhis-2/dhis-test-performance/src/test/org/hisp/dhis/test/tracker/TrackerTest.java index 7b400dc5fbf9..ddd71113f087 100644 --- a/dhis-2/dhis-test-performance/src/test/org/hisp/dhis/test/tracker/TrackerTest.java +++ b/dhis-2/dhis-test-performance/src/test/org/hisp/dhis/test/tracker/TrackerTest.java @@ -29,6 +29,7 @@ */ package org.hisp.dhis.test.tracker; +import static io.gatling.javaapi.core.CoreDsl.StringBody; import static io.gatling.javaapi.core.CoreDsl.constantConcurrentUsers; import static io.gatling.javaapi.core.CoreDsl.details; import static io.gatling.javaapi.core.CoreDsl.exec; @@ -52,7 +53,6 @@ public TrackerTest() { http.baseUrl("http://localhost:8080") .acceptHeader("application/json") .maxConnectionsPerHost(100) - .basicAuth("admin", "district") .header("Content-Type", "application/json") .userAgentHeader("Gatling/Performance Test") .warmUp( @@ -74,6 +74,11 @@ public TrackerTest() { scenario = scenario + .exec( + http("Login") + .post("/api/auth/login") + .body(StringBody("{\"username\":\"admin\",\"password\":\"district\"}")) + .check(status().is(200))) .repeat(Integer.parseInt(repeat)) .on( exec(http("Go to first page of program " + program) From 4dbe936234a2e550e549e14851cea60fbaa784cb Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 08:34:30 +0200 Subject: [PATCH 11/16] test: allow profiling in workflow --- .github/workflows/run-performance-tests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/run-performance-tests.yml b/.github/workflows/run-performance-tests.yml index 0eb1f29f18ed..5c58f4e4e4b8 100644 --- a/.github/workflows/run-performance-tests.yml +++ b/.github/workflows/run-performance-tests.yml @@ -41,6 +41,11 @@ on: required: false default: '' type: string + prof_args: + description: 'Profiler arguments (enables profiling). Options: https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilerOptions.md' + 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: @@ -96,6 +101,7 @@ jobs: DHIS2_IMAGE="${{ inputs.dhis2_image_baseline }}" \ SIMULATION_CLASS="${{ inputs.simulation_class }}" \ MVN_ARGS="${{ inputs.mvn_args }} -Dgatling.failOnError=false" \ + PROF_ARGS="${{ inputs.prof_args }}" \ DHIS2_DB_DUMP_URL="${{ inputs.dhis2_db_dump_url }}" \ DHIS2_DB_IMAGE_SUFFIX="${{ inputs.dhis2_db_image_suffix }}" \ ./run-simulation.sh @@ -105,6 +111,7 @@ jobs: DHIS2_IMAGE="${{ inputs.dhis2_image_candidate }}" \ SIMULATION_CLASS="${{ inputs.simulation_class }}" \ MVN_ARGS="${{ inputs.mvn_args }}" \ + PROF_ARGS="${{ inputs.prof_args }}" \ DHIS2_DB_DUMP_URL="${{ inputs.dhis2_db_dump_url }}" \ DHIS2_DB_IMAGE_SUFFIX="${{ inputs.dhis2_db_image_suffix }}" \ ./run-simulation.sh @@ -166,4 +173,7 @@ jobs: 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 + echo " * \`profile.html\` - Flamegraph visualization (if profiling enabled with prof_args)" >> $GITHUB_STEP_SUMMARY + echo " * \`profile.jfr\` - JFR profiler data (if profiling enabled with prof_args)" >> $GITHUB_STEP_SUMMARY + echo " * \`profile.collapsed\` - Collapsed stack traces (if profiling enabled with prof_args)" >> $GITHUB_STEP_SUMMARY From e40c622003db32bc0014e119d4c44fcf4b346358 Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 08:50:32 +0200 Subject: [PATCH 12/16] docs: readme --- dhis-2/dhis-test-performance/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dhis-2/dhis-test-performance/README.md b/dhis-2/dhis-test-performance/README.md index 6410d0f9e1b0..5e22b4693007 100644 --- a/dhis-2/dhis-test-performance/README.md +++ b/dhis-2/dhis-test-performance/README.md @@ -20,8 +20,9 @@ Test results are saved to `target/gatling/-/`: * `simulation.log` - Binary response times * `simulation.csv` - Response times (automated in CI only, [see below](#simulationcsv)) * `simulation-run.txt` - Run metadata -* `profile.html` - Flamegraph (when profiling enabled) -* `profile.jfr` - JFR (Java flight recorder) profiling data (when profiling enabled) +* `profile.html` - Flamegraph visualization (if profiling enabled with PROF_ARGS) +* `profile.jfr` - JFR profiler data (if profiling enabled with PROF_ARGS) +* `profile.collapsed` - Collapsed stack traces (if profiling enabled with PROF_ARGS) ### simulation.csv From 6bc067d23673a6a1e5ac80d82898cf2afe2643b9 Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 09:46:56 +0200 Subject: [PATCH 13/16] test: add DHIS2 image metadata like version to job summary --- .github/workflows/run-performance-tests.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/run-performance-tests.yml b/.github/workflows/run-performance-tests.yml index 5c58f4e4e4b8..46e192d3bea9 100644 --- a/.github/workflows/run-performance-tests.yml +++ b/.github/workflows/run-performance-tests.yml @@ -142,7 +142,27 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "Performance tests completed comparing:" >> $GITHUB_STEP_SUMMARY echo "* **Baseline**: \`${{ inputs.dhis2_image_baseline }}\`" >> $GITHUB_STEP_SUMMARY + + # Extract and display DHIS2 labels for baseline + OUTPUT=$(docker inspect -f '{{json .Config.Labels}}' "${{ inputs.dhis2_image_baseline }}" 2>/dev/null | \ + jq -r 'to_entries | map(select(.key | startswith("DHIS2_"))) | sort_by(.key) | .[] | " * **\(.key)**: `\(.value)`"') + if [ -z "$OUTPUT" ]; then + echo " * Failed to find DHIS2 related metadata in Docker image" >> $GITHUB_STEP_SUMMARY + else + echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY + fi + echo "* **Candidate**: \`${{ inputs.dhis2_image_candidate }}\`" >> $GITHUB_STEP_SUMMARY + + # Extract and display DHIS2 labels for candidate + OUTPUT=$(docker inspect -f '{{json .Config.Labels}}' "${{ inputs.dhis2_image_candidate }}" 2>/dev/null | \ + jq -r 'to_entries | map(select(.key | startswith("DHIS2_"))) | sort_by(.key) | .[] | " * **\(.key)**: `\(.value)`"') + if [ -z "$OUTPUT" ]; then + echo " * Failed to find DHIS2 related metadata in Docker image" >> $GITHUB_STEP_SUMMARY + else + echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY + fi + echo "* **Simulation Class**: \`${{ inputs.simulation_class }}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### 🖥️ Environment" >> $GITHUB_STEP_SUMMARY From 772e291e52568b406dde782d38aa0e38de71c07c Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 10:24:25 +0200 Subject: [PATCH 14/16] test: fix passing PROF_ARGS='-e wall -t' which must be passed as multiple args not a single one thus no double quoting --- dhis-2/dhis-test-performance/run-simulation.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dhis-2/dhis-test-performance/run-simulation.sh b/dhis-2/dhis-test-performance/run-simulation.sh index 4d6b438c4e21..7540d57bec78 100755 --- a/dhis-2/dhis-test-performance/run-simulation.sh +++ b/dhis-2/dhis-test-performance/run-simulation.sh @@ -135,10 +135,12 @@ post_process_profiler_data() { local title="$SIMULATION_CLASS on $DHIS2_IMAGE (async-profiler $PROF_ARGS)" # generate flamegraph and collapsed stack traces using jfrconv from async-profiler + # shellcheck disable=SC2086 docker compose exec --workdir /profiler-output web \ - jfrconv "$jfrconv_flags" --dot --title "$title" profile.jfr profile.html + jfrconv $jfrconv_flags --dot --title "$title" profile.jfr profile.html + # shellcheck disable=SC2086 docker compose exec --workdir /profiler-output web \ - jfrconv "$jfrconv_flags" --dot profile.jfr profile.collapsed + jfrconv $jfrconv_flags --dot profile.jfr profile.collapsed docker compose cp web:/profiler-output/. "$gatling_dir/" @@ -152,12 +154,14 @@ prepare_database() { start_profiler() { if [ -n "$PROF_ARGS" ]; then + # shellcheck disable=SC2086 docker compose exec --workdir /profiler-output web asprof start $PROF_ARGS -f profile.jfr 1 > /dev/null fi } run_simulation() { echo "Running $SIMULATION_CLASS..." + # shellcheck disable=SC2086 mvn gatling:test \ -Dgatling.simulationClass="$SIMULATION_CLASS" \ $MVN_ARGS From 10101f14fad79ba3841519dd2fab302055bde3fb Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 11:13:19 +0200 Subject: [PATCH 15/16] test: pull mutable images so they are up to date --- dhis-2/dhis-test-performance/run-simulation.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dhis-2/dhis-test-performance/run-simulation.sh b/dhis-2/dhis-test-performance/run-simulation.sh index 7540d57bec78..8bccfd92d15b 100755 --- a/dhis-2/dhis-test-performance/run-simulation.sh +++ b/dhis-2/dhis-test-performance/run-simulation.sh @@ -84,6 +84,21 @@ cleanup() { trap cleanup EXIT INT +pull_mutable_image() { + # Pull images with mutable tags to ensure we get the latest version. See + # https://github.com/dhis2/dhis2-core/blob/master/docker/DOCKERHUB.md for tag types. Mutable tags + # (dhis2/core-dev:*, dhis2/core-pr:*) are overwritten multiple times a day. Immutable tags + # (dhis2/core:2.42.1) are never rebuilt once published. Docker caches images locally, so without + # an explicit pull, we may run an outdated version even when using tags like 'latest' or 'master'. + # This is especially important on our self-hosted runner as devs will expect their latest change + # to be tested. + + if [[ "$DHIS2_IMAGE" =~ ^dhis2/core-(dev|pr): ]]; then + echo "Pulling mutable image tag: $DHIS2_IMAGE" + docker pull "$DHIS2_IMAGE" + fi +} + start_containers() { echo "Testing with image: $DHIS2_IMAGE" echo "Waiting for containers to be ready..." @@ -196,6 +211,7 @@ generate_metadata() { } > "$simulation_run_file" } +pull_mutable_image start_containers prepare_database start_profiler From 36dee4d74404aae6c049d051039b5f8f2c88425a Mon Sep 17 00:00:00 2001 From: teleivo Date: Thu, 2 Oct 2025 14:50:44 +0200 Subject: [PATCH 16/16] test: add command to job summary to reproduce --- .github/workflows/run-performance-tests.yml | 44 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-performance-tests.yml b/.github/workflows/run-performance-tests.yml index 46e192d3bea9..6e6ab2533c1d 100644 --- a/.github/workflows/run-performance-tests.yml +++ b/.github/workflows/run-performance-tests.yml @@ -140,7 +140,49 @@ jobs: run: | echo "## 🚀 Performance Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY + + # Build the command to reproduce this run + echo "### 🔄 Reproduce this run" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '```sh' >> $GITHUB_STEP_SUMMARY + echo -n 'gh workflow run run-performance-tests.yml' >> $GITHUB_STEP_SUMMARY + echo ' \' >> $GITHUB_STEP_SUMMARY + echo " --field perf_tests_git_ref=\"${{ inputs.perf_tests_git_ref }}\" \\" >> $GITHUB_STEP_SUMMARY + echo " --field simulation_class=\"${{ inputs.simulation_class }}\" \\" >> $GITHUB_STEP_SUMMARY + + # Add optional fields only if they're not empty or not default + if [ -n "${{ inputs.mvn_args }}" ]; then + echo " --field mvn_args=\"${{ inputs.mvn_args }}\" \\" >> $GITHUB_STEP_SUMMARY + fi + + if [ -n "${{ inputs.prof_args }}" ]; then + echo " --field prof_args=\"${{ inputs.prof_args }}\" \\" >> $GITHUB_STEP_SUMMARY + fi + + if [ "${{ inputs.dhis2_image_baseline }}" != "dhis2/core-dev:latest" ]; then + echo " --field dhis2_image_baseline=\"${{ inputs.dhis2_image_baseline }}\" \\" >> $GITHUB_STEP_SUMMARY + fi + + echo " --field dhis2_image_candidate=\"${{ inputs.dhis2_image_candidate }}\" \\" >> $GITHUB_STEP_SUMMARY + + if [ -n "${{ inputs.dhis2_db_dump_url }}" ]; then + echo " --field dhis2_db_dump_url=\"${{ inputs.dhis2_db_dump_url }}\" \\" >> $GITHUB_STEP_SUMMARY + fi + + if [ "${{ inputs.dhis2_db_image_suffix }}" != "sierra-leone-dev" ]; then + echo " --field dhis2_db_image_suffix=\"${{ inputs.dhis2_db_image_suffix }}\" \\" >> $GITHUB_STEP_SUMMARY + fi + + echo " --ref ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### 📊 Test Configuration" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY echo "Performance tests completed comparing:" >> $GITHUB_STEP_SUMMARY + echo "* **Simulation**" >> $GITHUB_STEP_SUMMARY + echo " * **Class**: \`${{ inputs.simulation_class }}\`" >> $GITHUB_STEP_SUMMARY + echo " * **Git ref**: \`${{ inputs.perf_tests_git_ref }}\`" >> $GITHUB_STEP_SUMMARY echo "* **Baseline**: \`${{ inputs.dhis2_image_baseline }}\`" >> $GITHUB_STEP_SUMMARY # Extract and display DHIS2 labels for baseline @@ -162,8 +204,6 @@ jobs: else echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY fi - - echo "* **Simulation Class**: \`${{ inputs.simulation_class }}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### 🖥️ Environment" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY