Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Containerization To Load Test #1130

Merged
merged 23 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6b82f16
Dockerize load tests
saquino0827 Jun 4, 2024
53c2e7d
Modified to regenerate submission id for every request, and handle ge…
basiliskus Jun 4, 2024
3c5606a
Added example ORM with required values for message linking
basiliskus Jun 4, 2024
77b6f76
refactoring of endpoints and teardown of docker containers
jorg3lopez Jun 5, 2024
9f51f92
Added error handling for authentication
basiliskus Jun 5, 2024
0d00d3e
Merge branch 'story/1121/fix-message-linking' into story/1121/dockeri…
saquino0827 Jun 5, 2024
d6ab7d1
Merge branch 'main' into story/1121/dockerize-load-tests
jorg3lopez Jun 5, 2024
8c1075f
update load tests dockerization to properly warm up orders & results …
saquino0827 Jun 5, 2024
0689c04
Merge branch 'story/1121/dockerize-load-tests' of https://github.com/…
saquino0827 Jun 5, 2024
4f55435
Merge branch 'main' into story/1121/dockerize-load-tests
basiliskus Jun 6, 2024
cc82f0f
Update load-test to warm up metadata
saquino0827 Jun 6, 2024
c058cdd
Merge branch 'story/1121/dockerize-load-tests' of https://github.com/…
saquino0827 Jun 6, 2024
3993fb0
use jq instead of awk for parsing jwt token
saquino0827 Jun 6, 2024
501c1ae
Update load-execute.sh
luis-pabon-tf Jun 6, 2024
1a9b3ac
Load test scripts available in docker and gradle with readme explanation
saquino0827 Jun 6, 2024
41f90b6
fix merge conflicts
saquino0827 Jun 6, 2024
6df30af
Merge branch 'main' into story/1121/dockerize-load-tests
saquino0827 Jun 7, 2024
27dea34
Finish warm-up for dockerized load testing
saquino0827 Jun 10, 2024
a54fe02
Merge branch 'story/1121/dockerize-load-tests' of https://github.com/…
saquino0827 Jun 10, 2024
4f51075
Merge branch 'main' into story/1121/dockerize-load-tests
saquino0827 Jun 11, 2024
63947bf
Load test auth endpoint checks and README.md updates for load test info
saquino0827 Jun 12, 2024
cc14305
PR updates
saquino0827 Jun 13, 2024
093963d
Update load test scripts with PR review fixes
saquino0827 Jun 14, 2024
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
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,15 @@ The `test` directory contains the tests. The `main` directory contains our cust

#### Load Testing

Load tests are completed with [Locust.io](https://docs.locust.io/en/stable/installation.html). Run the load tests by
running...
Load tests are completed with [Locust.io](https://docs.locust.io/en/stable/installation.html).
Run the load tests by running...

```shell
./load-execute.sh
./gradle-load-execute.sh

./docker-load-execute.sh
```
Currently, we are migrating to using Azure. Local load testing is using gradle, however a docker load test is available to mimic the Azure environment settings until the azure migration is complete.

This will run the API for you, so no need to run it manually.
**If you are already running the API, stop it before running the load tests or the cleanup steps won't work.**
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.postgres-test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "3.7"

services:
postgresql-test:
postgresql:
image: postgres:16
restart: unless-stopped
environment:
Expand Down
112 changes: 112 additions & 0 deletions docker-load-execute.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
set -e

local_port=5434

start_api() {
echo 'Starting API'
export DB_URL=postgresql
export DB_PORT=${local_port}
export DB_NAME=intermediary-test
export DB_USER=intermediary
export DB_PASS=changeIT!
export DB_SSL=require
export REPORT_STREAM_URL_PREFIX=
./gradlew shadowJar
docker compose up --build -d
export API_PID="${!}"
echo "API starting at PID ${API_PID}"
}

start_database() {
echo 'Starting database'
docker compose -f docker-compose.postgres-test.yml up -d
sleep 2
echo "Database started"
}
migrate_database() {
echo 'Migrating database'
liquibase update --changelog-file ./etor/databaseMigrations/root.yml --url jdbc:postgresql://localhost:${local_port}/intermediary-test --username intermediary --password 'changeIT!' --label-filter '!azure'
echo "Database migrated"
}

wait_for_api() {
attempt_counter=0
max_attempts=36

until curl --output /dev/null --silent --head --fail http://localhost:8080/health; do
if [ "${attempt_counter}" -eq "${max_attempts}" ];then
echo 'Done waiting for API to respond'
exit 1
fi
attempt_counter=$(($attempt_counter+1))
echo 'Waiting for API to respond'
sleep 5
done

echo 'API is responding'
}

warm_up_api() {
echo 'Warming up API...'
sleep 5
tokenPath=$(pwd)/mock_credentials/trusted-intermediary-valid-token.jwt
token=$(cat "${tokenPath}")

echo ${token}

echo 'Warming up auth...'
tiAuthResponse=$(curl --request POST "http://localhost:8080/v1/auth/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "scope=trusted-intermediary" \
--data-urlencode "client_assertion=${token}")

echo "$tiAuthResponse"
echo 'Retrieving access token...'

accessToken=$(echo "$tiAuthResponse" | grep -o '"access_token":"[^"]*' | grep -o '[^"]*$')

echo "$accessToken"

echo 'Warming up results...'
resultFile=$(pwd)/examples/Test/e2e/results/001_ORU_R01_short.fhir
curl --silent --request POST "http://localhost:8080/v1/etor/results" \
--header "recordId: 6789" \
--header "Authorization: Bearer ${accessToken}" \
--data-binary "@${resultFile}"

echo 'Warming up orders...'
orderFile=$(pwd)/examples/Test/e2e/orders/002_ORM_O01_short.fhir
curl --silent --request POST "http://localhost:8080/v1/etor/orders" \
--header "recordId: 1234" \
--header "Authorization: Bearer ${accessToken}" \
--data-binary "@${orderFile}"

echo 'Warm up nap time...'
sleep 5

echo 'API is cozy'
}

run_tests() {
echo 'Running the load test'
locust --headless -f ./operations/locustfile.py -H http://localhost:8080 -u 1000 -r 15 -t 5m
}

cleanup() {
echo "Stopping API docker container"
docker compose down
echo "API Docker container stopped"
echo "Stopping and deleting database"
docker compose -f docker-compose.postgres-test.yml down -v
echo "Database stopped and deleted"
}

trap cleanup EXIT # Run the cleanup function on exit
start_database
migrate_database
start_api
wait_for_api
warm_up_api
warm_up_api
run_tests
111 changes: 111 additions & 0 deletions gradle-load-execute.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
set -e

local_port=5434

start_api() {
echo 'Starting API'
export DB_URL=localhost
export DB_PORT=${local_port}
export DB_NAME=intermediary-test
export DB_USER=intermediary
export DB_PASS=changeIT!
export DB_SSL=require
export REPORT_STREAM_URL_PREFIX=
./gradlew --no-daemon app:clean app:run > /dev/null 2>&1 &
export API_PID="${!}"
echo "API starting at PID ${API_PID}"
}

start_database() {
echo 'Starting database'
docker compose -f docker-compose.postgres-test.yml up -d
sleep 2
echo "Database started"
}

migrate_database() {
echo 'Migrating database'
liquibase update --changelog-file ./etor/databaseMigrations/root.yml --url jdbc:postgresql://localhost:${local_port}/intermediary-test --username intermediary --password 'changeIT!' --label-filter '!azure'
echo "Database migrated"
}

wait_for_api() {
attempt_counter=0
max_attempts=36

until curl --output /dev/null --silent --head --fail http://localhost:8080/health; do
if [ "${attempt_counter}" -eq "${max_attempts}" ];then
echo 'Done waiting for API to respond'
exit 1
fi
attempt_counter=$(($attempt_counter+1))
echo 'Waiting for API to respond'
sleep 5
done

echo 'API is responding'
}

warm_up_api() {
echo 'Warming up API...'
sleep 5
tokenPath=$(pwd)/mock_credentials/trusted-intermediary-valid-token.jwt
token=$(cat "${tokenPath}")

echo ${token}

echo 'Warming up auth...'
tiAuthResponse=$(curl --request POST "http://localhost:8080/v1/auth/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "scope=trusted-intermediary" \
--data-urlencode "client_assertion=${token}")

echo "$tiAuthResponse"
echo 'Retrieving access token...'

accessToken=$(echo "$tiAuthResponse" | grep -o '"access_token":"[^"]*' | grep -o '[^"]*$')

echo "$accessToken"

echo 'Warming up results...'
resultFile=$(pwd)/examples/Test/e2e/results/001_ORU_R01_short.fhir
curl --silent --request POST "http://localhost:8080/v1/etor/results" \
--header "recordId: 6789" \
--header "Authorization: Bearer ${accessToken}" \
--data-binary "@${resultFile}"

echo 'Warming up orders...'
orderFile=$(pwd)/examples/Test/e2e/orders/002_ORM_O01_short.fhir
curl --silent --request POST "http://localhost:8080/v1/etor/orders" \
--header "recordId: 1234" \
--header "Authorization: Bearer ${accessToken}" \
--data-binary "@${orderFile}"

echo 'Warm up nap time...'
sleep 5

echo 'API is cozy'
}

run_tests() {
echo 'Running the load test'
locust --headless -f ./operations/locustfile.py -H http://localhost:8080 -u 1000 -r 17 -t 5m
}

cleanup() {
echo "Killing API at PID ${API_PID}"
kill "${API_PID}"
echo "PID ${API_PID} killed"
echo "Stopping and deleting database"
docker compose -f docker-compose.postgres-test.yml down -v
echo "Database stopped and deleted"
}

trap cleanup EXIT # Run the cleanup function on exit
start_database
migrate_database
start_api
wait_for_api
warm_up_api
run_tests
68 changes: 0 additions & 68 deletions load-execute.sh

This file was deleted.

2 changes: 1 addition & 1 deletion operations/locustfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def authenticate(self):
else:
logging.error(f"Authentication failed: {response.error}")

@task
@task(1)
def get_health(self):
self.client.get(HEALTH_ENDPOINT)

Expand Down