Skip to content

Commit aa81408

Browse files
authored
🔨♻️Performance testing: upgrade locust infrastructure (#7711)
1 parent c13a946 commit aa81408

36 files changed

+765
-771
lines changed

scripts/common.Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
# defaults
1616
.DEFAULT_GOAL := help
1717

18+
# Colors
19+
BLUE=\033[0;34m
20+
GREEN=\033[0;32m
21+
YELLOW=\033[0;33m
22+
RED=\033[0;31m
23+
NC=\033[0m # No Color
24+
1825
# Use bash not sh
1926
SHELL := /bin/bash
2027

tests/performance/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Ignore credentials file
2+
.auth-credentials.env
3+
4+
# Ignore all locust configuration files
5+
.locust.conf*
6+
7+
# ignore test reports
8+
*.html

tests/performance/Dockerfile

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/performance/Makefile

Lines changed: 143 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,153 @@
11
#
2-
# Targets for DEVELOPMENT for performance test web-api
2+
# Targets for DEVELOPMENT of tests/public-api
33
#
44
include ../../scripts/common.Makefile
5-
6-
LOCUST_VERSION=2.29.1
7-
export LOCUST_VERSION
8-
9-
ENV_FILE=$(shell pwd)/.env
10-
export ENV_FILE
11-
12-
KERNEL_NAME=$(shell uname -s)
13-
14-
NETWORK_NAME=dashboards_timenet
15-
16-
TEST_IMAGE_NAME := itisfoundation/performance-tests
17-
TEST_IMAGE_TAG := v0
18-
19-
# UTILS
20-
# NOTE: keep short arguments for `cut` so it works in both BusyBox (alpine) AND Ubuntu
21-
get_my_ip := $(shell (hostname --all-ip-addresses || hostname -i) 2>/dev/null | cut -d " " -f 1)
22-
23-
# Check that given variables are set and all have non-empty values,
24-
# die with an error otherwise.
25-
#
26-
# Params:
27-
# 1. Variable name(s) to test.
28-
# 2. (optional) Error message to print.
29-
check_defined = \
30-
$(strip $(foreach 1,$1, \
31-
$(call __check_defined,$1,$(strip $(value 2)))))
32-
__check_defined = \
33-
$(if $(value $1),, \
34-
$(error Undefined $1$(if $2, ($2))))
35-
36-
37-
38-
.PHONY: build
39-
build: ## builds distributed osparc locust docker image
40-
docker \
41-
buildx build \
42-
--load \
43-
--build-arg LOCUST_VERSION=$(LOCUST_VERSION) \
44-
--tag itisfoundation/locust:$(LOCUST_VERSION) \
45-
--tag local/locust:latest \
46-
.
47-
48-
.PHONY: push
49-
push:
50-
docker push itisfoundation/locust:$(LOCUST_VERSION)
51-
52-
.PHONY: test-up test-down
53-
test-up: ## runs osparc locust. Locust and test configuration are specified in ENV_FILE
54-
@if [ ! -f $${ENV_FILE} ]; then echo "You must generate a .env file before running tests!!! See the README..." && exit 1; fi;
55-
@if ! docker network ls | grep -q $(NETWORK_NAME); then \
56-
docker network create $(NETWORK_NAME); \
57-
echo "Created docker network $(NETWORK_NAME)"; \
5+
include ../../scripts/common-package.Makefile
6+
7+
8+
9+
.PHONY: install-dev install-prod install-ci
10+
install-dev install-prod install-ci: _check_venv_active ## install app in development/production or CI mode
11+
# installing in $(subst install-,,$@) mode
12+
@uv pip sync requirements/$(subst install-,,$@).txt
13+
14+
15+
# Configuration files and default values
16+
LOCUST_CONFIG_FILE := .locust.conf
17+
AUTH_CREDS_FILE := .auth-credentials.env
18+
19+
# Default Database settings
20+
PG_HOST := 127.0.0.1
21+
PG_PORT := 5432
22+
PG_USER := postgres
23+
PG_PASSWORD := password
24+
25+
# Default Grafana settings
26+
GRAFANA_URL := http://127.0.0.1:3000/
27+
28+
# Default Locust test settings
29+
DEFAULT_PROCESSES := 4
30+
DEFAULT_USERS := 10
31+
DEFAULT_SPAWN_RATE := 1
32+
DEFAULT_RUN_TIME := 1m
33+
DEFAULT_HOST := http://127.0.0.1:9081
34+
35+
36+
37+
define create_locust_config
38+
@if [ ! -f $(LOCUST_CONFIG_FILE) ]; then \
39+
printf "$(YELLOW)First time setup: Creating Locust configuration file$(NC)\n"; \
40+
printf "Available locust files in locustfiles/:\n"; \
41+
find locustfiles -maxdepth 1 -type f -name '*.py' ! -name '__init__.py' -printf ' %p\n'; \
42+
find locustfiles -mindepth 2 -type f -name 'workflow.py' -printf ' %p\n'; \
43+
read -p "Locust file to use [./locustfiles/deployment_max_rps_single_endpoint.py]: " locustfile; \
44+
locustfile=$${locustfile:-./locustfiles/deployment_max_rps_single_endpoint.py}; \
45+
read -p "Number of processes [$(DEFAULT_PROCESSES)]: " processes; \
46+
processes=$${processes:-$(DEFAULT_PROCESSES)}; \
47+
read -p "Number of users [$(DEFAULT_USERS)]: " users; \
48+
users=$${users:-$(DEFAULT_USERS)}; \
49+
read -p "Spawn rate [$(DEFAULT_SPAWN_RATE)]: " spawn_rate; \
50+
spawn_rate=$${spawn_rate:-$(DEFAULT_SPAWN_RATE)}; \
51+
read -p "Run time [$(DEFAULT_RUN_TIME)]: " run_time; \
52+
run_time=$${run_time:-$(DEFAULT_RUN_TIME)}; \
53+
read -p "Host to load test [$(DEFAULT_HOST)]: " host; \
54+
host=$${host:-$(DEFAULT_HOST)}; \
55+
echo; \
56+
echo "# Locust configuration file - Autogenerated" > $(LOCUST_CONFIG_FILE); \
57+
echo "[locust]" >> $(LOCUST_CONFIG_FILE); \
58+
echo "locustfile = $$locustfile" >> $(LOCUST_CONFIG_FILE); \
59+
echo "host = $$host" >> $(LOCUST_CONFIG_FILE); \
60+
echo "users = $$users" >> $(LOCUST_CONFIG_FILE); \
61+
echo "spawn-rate = $$spawn_rate" >> $(LOCUST_CONFIG_FILE); \
62+
echo "run-time = $$run_time" >> $(LOCUST_CONFIG_FILE); \
63+
echo "processes = $$processes" >> $(LOCUST_CONFIG_FILE); \
64+
echo "loglevel = INFO" >> $(LOCUST_CONFIG_FILE); \
65+
echo "" >> $(LOCUST_CONFIG_FILE); \
66+
printf "$(GREEN)Locust configuration file created. It won't be asked again.$(NC)\n"; \
67+
else \
68+
printf "$(GREEN)Using existing Locust configuration file $(LOCUST_CONFIG_FILE)$(NC)\n"; \
5869
fi
59-
docker compose --file docker-compose.yml up --scale worker=4 --exit-code-from=master
60-
61-
test-down: ## stops and removes osparc locust containers
62-
@docker compose --file docker-compose.yml down
63-
64-
.PHONY: dashboards-up dashboards-down
65-
66-
dashboards-up: ## Create Grafana dashboard for inspecting locust results. See dashboard on localhost:3000
67-
@echo "View your dashboard on localhost:3000"
68-
@if docker network ls | grep -q $(NETWORK_NAME); then \
69-
docker network rm $(NETWORK_NAME); \
70-
echo "Removed docker network $(NETWORK_NAME)"; \
70+
endef
71+
72+
# Function to prompt for credentials if they don't exist
73+
define prompt_for_credentials
74+
@if [ ! -f $(AUTH_CREDS_FILE) ]; then \
75+
printf "$(YELLOW)First time setup: Please enter the deployment credentials$(NC)\n"; \
76+
read -p "Username: " username; \
77+
read -sp "Password: " password; \
78+
echo; \
79+
echo "SC_USER_NAME=$$username" > $(AUTH_CREDS_FILE); \
80+
echo "SC_PASSWORD=$$password" >> $(AUTH_CREDS_FILE); \
81+
read -p "osparc Username (required if login in osparc is necessary, press enter to skip): " osparc_username; \
82+
if [ ! -z "$$osparc_username" ]; then \
83+
read -sp "osparc Password: " osparc_password; \
84+
echo; \
85+
echo "OSPARC_USER_NAME=$$osparc_username" >> $(AUTH_CREDS_FILE); \
86+
echo "OSPARC_PASSWORD=$$osparc_password" >> $(AUTH_CREDS_FILE); \
87+
fi; \
88+
printf "$(GREEN)Credentials saved. They won't be asked again.$(NC)\n"; \
89+
else \
90+
printf "$(GREEN)Using cached credentials from $(AUTH_CREDS_FILE)$(NC)\n"; \
7191
fi
72-
@if [[ "$(KERNEL_NAME)" == "Linux" ]]; then \
73-
( sleep 3 && xdg-open http://localhost:3000 ) & \
92+
endef
93+
94+
95+
test-deployment: _check_venv_active ## runs deployment test on deploy
96+
@$(call prompt_for_credentials)
97+
@$(call create_locust_config)
98+
@printf "$(YELLOW)Starting Locust...$(NC)\n"
99+
@xdg-open http://localhost:8089/ &
100+
@export $$(cat $(AUTH_CREDS_FILE) | xargs) && \
101+
locust --config $(LOCUST_CONFIG_FILE)
102+
103+
test-deployment-ci: _check_venv_active $(AUTH_CREDS_FILE) $(LOCUST_CONFIG_FILE) ## runs deployment test on CI, expects all config and credentials files to be present, does not prompt
104+
@printf "$(YELLOW)Starting Locust headless...$(NC)\n"
105+
@export $$(cat $(AUTH_CREDS_FILE) | xargs) && \
106+
locust --config $(LOCUST_CONFIG_FILE) \
107+
--headless \
108+
--html test_report_{u}users_{r}userspawnrate_{t}s.html
109+
110+
test-deployment-with-grafana: _check_venv_active grafana-dashboards-up ## runs deployment test with Grafana integration
111+
@$(call prompt_for_credentials)
112+
@$(call create_locust_config)
113+
@printf "$(YELLOW)Starting Locust with Grafana integration...$(NC)\n"
114+
@xdg-open $(GRAFANA_URL)
115+
@export $$(cat $(AUTH_CREDS_FILE) | xargs) && \
116+
locust --config $(LOCUST_CONFIG_FILE) \
117+
--grafana-url $(GRAFANA_URL) \
118+
--pghost $(PG_HOST) \
119+
--pgport $(PG_PORT) \
120+
--pguser $(PG_USER) \
121+
--pgpassword=$(PG_PASSWORD) \
122+
--headless \
123+
--timescale
124+
125+
126+
127+
128+
clear-credentials: ## Clear the cached authentication credentials
129+
@if [ -f $(AUTH_CREDS_FILE) ]; then \
130+
rm $(AUTH_CREDS_FILE); \
131+
printf "$(GREEN)Credentials cleared.$(NC)\n"; \
132+
else \
133+
printf "$(YELLOW)No credentials file found.$(NC)\n"; \
74134
fi
75-
@locust-compose up
76-
77-
78-
dashboards-down: ## stops and removes Grafana dashboard and Timescale postgress containers
79-
@locust-compose down
80-
81-
.PHONY: install-ci install-dev
82135

83-
install-dev:
84-
@uv pip install -r requirements/requirements-dev.txt
85136

86-
install-ci:
87-
@uv pip install -r requirements/requirements-ci.txt
137+
clear: down clear-credentials clear-locust-config ## Clear all cached data including credentials and Locust configuration files
88138

139+
clear-locust-config: ## Clear all Locust configuration files
140+
@for config_file in $(LOCUST_CONFIG_FILE) $(LOCUST_CONFIG_FILE)_light $(LOCUST_CONFIG_FILE)_heavy; do \
141+
if [ -f $$config_file ]; then \
142+
rm $$config_file; \
143+
printf "$(GREEN)$$config_file cleared.$(NC)\n"; \
144+
fi; \
145+
done
146+
@if [ ! -f $(LOCUST_CONFIG_FILE) ] && [ ! -f $(LOCUST_CONFIG_FILE)_light ] && [ ! -f $(LOCUST_CONFIG_FILE)_heavy ]; then \
147+
printf "$(YELLOW)No Locust configuration files found.$(NC)\n"; \
148+
fi
89149

90-
.PHONY: config
91-
config: ## Create config for your locust tests
92-
@$(call check_defined, input, please define inputs when calling $@ - e.g. ```make $@ input="--help"```)
93-
@uv run locust_settings.py $(input) | tee "${ENV_FILE}"
94-
95-
96-
.PHONY: build-test-image push-test-image
97-
build-test-image: _check_venv_active ## Build test image
98-
docker build --build-arg PYTHON_VERSION="$(shell python --version | cut -d' ' -f2)" --build-arg UV_VERSION="$(shell uv --version | cut -d' ' -f2)" -t ${TEST_IMAGE_NAME}:${TEST_IMAGE_TAG} ./docker
99-
100-
push-test-image: ## Push test image to dockerhub
101-
docker push ${TEST_IMAGE_NAME}:${TEST_IMAGE_TAG}
150+
grafana-dashboards-up: ## start grafana dashboards for locust
151+
@locust-compose up -d
152+
down grafana-dashboards-down: ## stop grafana dashboards for locust
153+
@locust-compose down

tests/performance/README.md

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,91 @@
1-
# performance testing using [locust.io](https://docs.locust.io/en/stable/index.html)
1+
# osparc-simcore Performance Test Suite
22

3-
Locust allows simple testing of endpoints, and checks for response time, response type. It also allows to create useful reports.
3+
This directory contains performance testing tools and scripts for osparc-simcore, using [Locust](https://locust.io/) for load testing. The suite is designed for both interactive (developer) and CI (automation) usage, with robust credential/config prompts and support for result visualization in Grafana.
44

5-
## configuration
5+
## Makefile Targets
66

7-
In the [locust_files] folder are located the test files.
7+
All main operations are managed via the provided `Makefile`. Ensure you have a Python virtual environment activated and all dependencies installed before running the targets.
88

9-
## Usage
9+
### Main Targets
1010

11-
1. All settings are passed to the locust container as environment variables in `.env`. To generate locust env vars, run `make config` with appropriate `input`. To see what the possible settings are, run `make config input="--help"`. E.g. you could run
12-
```bash
13-
make config input="--LOCUST_HOST=https://api.osparc-master.speag.com
14-
--LOCUST_USERS=100 --LOCUST_RUN_TIME=0:10:00 --LOCUST_LOCUSTFILE=locust_files/platform_ping_test.py"
15-
```
16-
This will validate your settings and you should be good to go once you see a the settings printed in your terminal.
11+
- **`make test-deployment`**
12+
Interactively prompts for credentials and Locust configuration, then runs a Locust test. If required files are missing, you will be prompted for:
13+
- SC (Simcore) username and password
14+
- Optionally, OSPARC username and password (press Enter to skip)
15+
- Locust configuration (target host, users, etc.)
16+
- Locust file selection: a list of available `.py` files (excluding `__init__.py`) and `workflow.py` in subfolders will be shown; enter the path to the desired file.
1717

18-
2. Once you have all settings setup you run your test script using the Make `test` recipe:
19-
```bash
20-
make test-up
21-
```
18+
- **`make test-deployment-with-grafana`**
19+
Like `test-deployment`, but also starts Grafana dashboards for monitoring. Prompts for credentials and configuration if needed.
20+
21+
- **`make test-deployment-ci`**
22+
Runs a Locust test in CI mode. Expects `.auth-credentials.env` and `.locust.conf` to already exist (no prompts). Fails if these files are missing. Use this for automation and CI pipelines.
23+
24+
- **`make clear-credentials`**
25+
Removes cached credentials (`.auth-credentials.env`).
26+
27+
- **`make clear-locust-config`**
28+
Removes Locust configuration files (`.locust.conf`).
29+
30+
- **`make clear`**
31+
Removes both credentials and Locust config files.
32+
33+
34+
35+
## Locust File Selection
36+
37+
When prompted to select a Locust file, the script will list all available `.py` files (excluding `__init__.py`) and any `workflow.py` in subfolders. Enter the path to the file you wish to use (e.g., `locustfiles/deployment_max_rps_single_endpoint.py`).
38+
39+
## Visualizing Test Results with Locust UI
2240

23-
3. If you want to clean up after your tests (remove docker containers) you run `make test-down`
41+
When running Locust (`make test-deployment`), open the following website in your browser to visualize the performance test dashboards:
42+
43+
- [http://127.0.0.1:8089/](http://127.0.0.1:8089/)
44+
45+
## Visualizing Test Results with Grafana
46+
47+
When running with Grafana integration (`make test-deployment-with-grafana`), open the following website in your browser to visualize the performance test dashboards:
48+
49+
- [http://127.0.0.1:3000/](http://127.0.0.1:3000/)
50+
51+
## Example: Running in CI
52+
53+
To use the `test-deployment-ci` target in a CI pipeline (e.g., GitLab CI), you must first generate the required files non-interactively. For example:
54+
55+
```sh
56+
# Set credentials as environment variables (in CI, use CI/CD secrets)
57+
export SC_USER_NAME=youruser
58+
export SC_PASSWORD=yourpass
59+
# Optionally for osparc login
60+
export OSPARC_USER_NAME=osparcuser
61+
export OSPARC_PASSWORD=osparcpass
62+
63+
# Create the credentials file
64+
cat <<EOF > .auth-credentials.env
65+
SC_USER_NAME=$SC_USER_NAME
66+
SC_PASSWORD=$SC_PASSWORD
67+
OSPARC_USER_NAME=$OSPARC_USER_NAME
68+
OSPARC_PASSWORD=$OSPARC_PASSWORD
69+
EOF
70+
71+
# Create a Locust config file (adjust locustfile path as needed)
72+
cat <<EOF > .locust.conf
73+
[locust]
74+
locustfile = ./locustfiles/deployment_max_rps_single_endpoint.py
75+
host = http://127.0.0.1:9081
76+
users = 10
77+
spawn-rate = 1
78+
run-time = 5m
79+
processes = 4
80+
loglevel = INFO
81+
EOF
82+
83+
# Run the CI target
84+
make test-deployment-ci
85+
```
2486

25-
## Dashboards for visualization
26-
- You can visualize the results of your tests (in real time) in a collection of beautiful [Grafana dashboards](https://github.com/SvenskaSpel/locust-plugins/tree/master/locust_plugins/dashboards).
27-
- To do this, run `make dashboards-up`. If you are on linux you should see your browser opening `localhost:3000`, where you can view the dashboards. If the browser doesn't open automatically, do it manually and navigate to `localhost:3000`.The way you tell locust to send test results to the database/grafana is by ensuring `LOCUST_TIMESCALE=1` (see how to generate settings in [usage](#usage))
28-
- When you are done you run `make dashboards-down` to clean up.
29-
- If you are using VPN you will need to forward port 3000 to your local machine to view the dashboard.
87+
In a GitLab CI YAML job, you can use these steps in the `script:` section, using CI/CD variables for secrets.
3088

89+
---
3190

32-
## Tricky settings 🚨
33-
- `LOCUST_TIMESCALE` tells locust whether or not to send data to the database associated with visualizing the results. If you are not using the Grafana [dashboards](#dashboards-for-visualization) you should set `LOCUST_TIMESCALE=0`.
91+
For more details, see the Makefile and comments in this directory. If you encounter issues or need to update the workflow, please refer to the latest Makefile and scripts for guidance.
File renamed without changes.

0 commit comments

Comments
 (0)