Skip to content

Commit fedb161

Browse files
✨ Integrate locust dashboards (#6047)
1 parent a3f5591 commit fedb161

12 files changed

+115
-27
lines changed

tests/performance/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ RUN pip3 --version && \
77
pip3 install \
88
faker \
99
locust-plugins \
10+
locust-plugins[dashboards] \
1011
pydantic \
1112
pydantic-settings \
1213
tenacity &&\

tests/performance/Makefile

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ include ../../scripts/common.Makefile
66
LOCUST_VERSION=2.29.1
77
export LOCUST_VERSION
88

9+
ENV_FILE=$(shell pwd)/.env
10+
export ENV_FILE
11+
12+
NETWORK_NAME=dashboards_timenet
13+
914
# UTILS
1015
get_my_ip := $(shell (hostname --all-ip-addresses || hostname -i) 2>/dev/null | cut --delimiter=" " --fields=1)
1116

@@ -36,14 +41,32 @@ down: ## stops and removes osparc locust containers
3641
docker compose --file docker-compose.yml down
3742

3843
.PHONY: test
39-
test: ## runs osparc locust. locust and test confiuration are specified in .env file next to target file
40-
@$(call check_defined, target, please define target file when calling $@ - e.g. ```make $@ target=MY_LOCUST_FILE.py```)
41-
@export LOCUST_FILE=$(target); \
42-
export ENV_FILE=$$(realpath .env); \
43-
if [ ! -f $${ENV_FILE} ]; then echo "You must generate a .env file before running tests!!! See the README..." && exit 1; fi; \
44+
test: ## runs osparc locust. Locust and test configuration are specified in ENV_FILE
45+
@if [ ! -f $${ENV_FILE} ]; then echo "You must generate a .env file before running tests!!! See the README..." && exit 1; fi;
46+
@if ! docker network ls | grep -q $(NETWORK_NAME); then \
47+
docker network create $(NETWORK_NAME); \
48+
echo "Created docker network $(NETWORK_NAME)"; \
49+
fi
4450
docker compose --file docker-compose.yml up --scale worker=4 --exit-code-from=master
4551

52+
.PHONY: install-ci install-dev install
4653

47-
.PHONY: install-dev
48-
install-dev: _check_venv_active ## install python tools
54+
install-dev: install
55+
install-ci: install
56+
57+
install: _check_venv_active ## install python tools
4958
@uv pip install -r requirements.txt
59+
60+
61+
.PHONY: dashboards-up dashboards-down
62+
63+
dashboards-up: ## Create Grafana dashboard for inspecting locust results. See dashboard on localhost:3000
64+
@echo "View your dashboard on localhost:3000"
65+
@if docker network ls | grep -q $(NETWORK_NAME); then \
66+
docker network rm $(NETWORK_NAME); \
67+
echo "Removed docker network $(NETWORK_NAME)"; \
68+
fi
69+
@locust-compose up
70+
71+
dashboards-down:
72+
@locust-compose down

tests/performance/README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,22 @@ In the [locust_files] folder are located the test files.
88

99
## Usage
1010

11-
1. Generate a `.env` file with setting for your test. After running `make install-dev` you can execute your test script in python and set settings as arguments. Once your settings are validated you pipe them to `.env`, e.g.
11+
1. Generate a `.env` file with setting for your test. After running `make install-dev` you can execute your test script in python and set settings as arguments. Once your settings are validated you pipe them to `.env`. E.g. if your testscript is `locust_files/platform_ping_test.py` you could run
1212
```bash
1313
python locust_files/platform_ping_test.py --LOCUST_HOST=https://api.osparc-master.speag.com \
1414
--LOCUST_USERS=100 --LOCUST_RUN_TIME=0:10:00 --SC_USER_NAME=myname --SC_PASSWORD=mypassword > .env
1515
```
16-
2. Run your test script using the Make `test` recipe, setting the correct `target`, e.g.
16+
2. Run your test script using the Make `test` recipe, e.g.
1717
```
18-
make test target=locust_files/platform_ping_test.py
18+
make test
1919
```
20+
21+
## Dashboards for visualization
22+
- 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).
23+
- To do this, run `make dashboards-up` and go to `localhost:3000` to view the dashboards. 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))
24+
- When you are done you run `make dashboards-down` to clean up.
25+
- If you are using VPN you will need to forward port 300 to your local machine to view the dashboard.
26+
27+
28+
## Tricky settings 🚨
29+
- `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`.

tests/performance/docker-compose.yml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@ services:
44
ports:
55
- "8089:8089"
66
volumes:
7-
- ./locust_files:/mnt/locust_files
8-
- ./locust_report:/mnt/locust_report
7+
- ./locust_files:/home/locust/locust_files
8+
- ./locust_report:/home/locust/locust_report
99
command: >
10-
-f /mnt/${LOCUST_FILE} --html /mnt/locust_report/locust_html.html --master
10+
--master --html=locust_report/locust_html.html
1111
env_file:
1212
- ${ENV_FILE}
13+
networks:
14+
- dashboards_timenet
1315

1416
worker:
1517
image: itisfoundation/locust:${LOCUST_VERSION}
1618
volumes:
17-
- ./locust_files/:/mnt/locust_files
19+
- ./locust_files/:/home/locust/locust_files
1820
command: >
19-
-f /mnt/${LOCUST_FILE} --worker --master-host master
21+
--worker --master-host master
2022
env_file:
2123
- ${ENV_FILE}
24+
networks:
25+
- dashboards_timenet
26+
27+
networks:
28+
dashboards_timenet :
29+
external: true
30+
name: dashboards_timenet

tests/performance/locust_files/catalog_services.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
import logging
6+
from pathlib import Path
67
from time import time
78

89
import faker
@@ -60,4 +61,8 @@ def on_stop(self):
6061
if __name__ == "__main__":
6162
from locust_settings import LocustSettings, dump_dotenv
6263

63-
dump_dotenv(LocustSettings())
64+
dump_dotenv(
65+
LocustSettings(
66+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
67+
)
68+
)

tests/performance/locust_files/director_services.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
import logging
6+
from pathlib import Path
67

78
from locust import task
89
from locust.contrib.fasthttp import FastHttpUser
@@ -34,4 +35,8 @@ def on_stop(self): # pylint: disable=no-self-use
3435
if __name__ == "__main__":
3536
from locust_settings import LocustSettings, dump_dotenv
3637

37-
dump_dotenv(LocustSettings())
38+
dump_dotenv(
39+
LocustSettings(
40+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
41+
)
42+
)

tests/performance/locust_files/locustfile.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
import logging
6+
from pathlib import Path
67
from uuid import UUID
78

89
import faker
@@ -82,4 +83,8 @@ def on_stop(self):
8283
class LoadTestSettings(TemplateSettings, LocustSettings):
8384
pass
8485

85-
dump_dotenv(LoadTestSettings())
86+
dump_dotenv(
87+
LoadTestSettings(
88+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
89+
)
90+
)

tests/performance/locust_files/metamodeling/workflow.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,10 @@ def upload_file(self, file: Path) -> UUID:
171171
class MetaModelingSettings(UserSettings, LocustSettings):
172172
pass
173173

174-
dump_dotenv(MetaModelingSettings())
174+
dump_dotenv(
175+
MetaModelingSettings(
176+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(
177+
Path(__file__).parent.parent.parent
178+
)
179+
)
180+
)

tests/performance/locust_files/platform_ping_test.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
import logging
6+
from pathlib import Path
67

78
import locust_plugins
89
from locust import task
@@ -58,4 +59,8 @@ def on_stop(self): # pylint: disable=no-self-use
5859
class LoadTestSettings(LocustAuth, LocustSettings):
5960
pass
6061

61-
dump_dotenv(LoadTestSettings())
62+
dump_dotenv(
63+
LoadTestSettings(
64+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
65+
)
66+
)

tests/performance/locust_files/user_basic_calls.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import logging
66
import time
7+
from pathlib import Path
78

89
import faker
910
from locust import task
@@ -96,4 +97,8 @@ def on_stop(self):
9697
if __name__ == "__main__":
9798
from locust_settings import LocustSettings, dump_dotenv
9899

99-
dump_dotenv(LocustSettings())
100+
dump_dotenv(
101+
LocustSettings(
102+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
103+
)
104+
)

tests/performance/locust_files/webserver_services.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
import logging
6+
from pathlib import Path
67

78
import faker
89
from dotenv import load_dotenv
@@ -54,4 +55,8 @@ def on_stop(self):
5455
if __name__ == "__main__":
5556
from locust_settings import LocustSettings, dump_dotenv
5657

57-
dump_dotenv(LocustSettings())
58+
dump_dotenv(
59+
LocustSettings(
60+
LOCUST_LOCUSTFILE=Path(__file__).relative_to(Path(__file__).parent.parent)
61+
)
62+
)

tests/performance/settings/locust_settings/_locust_settings.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
# pylint: disable=no-name-in-module
44

55
from datetime import timedelta
6+
from pathlib import Path
67

78
from parse import Result, parse
89
from pydantic import (
910
AnyHttpUrl,
1011
Field,
12+
NonNegativeInt,
1113
PositiveFloat,
1214
PositiveInt,
1315
SerializationInfo,
@@ -22,16 +24,23 @@
2224
class LocustSettings(BaseSettings):
2325
model_config = SettingsConfigDict(cli_parse_args=True)
2426

27+
LOCUST_CHECK_AVG_RESPONSE_TIME: PositiveInt = Field(default=200)
28+
LOCUST_CHECK_FAIL_RATIO: PositiveFloat = Field(default=0.01, ge=0.0, le=1.0)
29+
LOCUST_HEADLESS: bool = Field(default=True)
2530
LOCUST_HOST: AnyHttpUrl = Field(
2631
default=..., examples=["https://api.osparc-master.speag.com"]
2732
)
28-
LOCUST_USERS: PositiveInt = Field(default=...)
29-
LOCUST_HEADLESS: bool = Field(default=True)
33+
LOCUST_LOCUSTFILE: Path = Field(default=...)
3034
LOCUST_PRINT_STATS: bool = Field(default=True)
31-
LOCUST_SPAWN_RATE: PositiveInt = Field(default=20)
3235
LOCUST_RUN_TIME: timedelta = Field(default=...)
33-
LOCUST_CHECK_AVG_RESPONSE_TIME: PositiveInt = Field(default=200)
34-
LOCUST_CHECK_FAIL_RATIO: PositiveFloat = Field(default=0.01, ge=0.0, le=1.0)
36+
LOCUST_SPAWN_RATE: PositiveInt = Field(default=20)
37+
LOCUST_TIMESCALE: NonNegativeInt = Field(default=1, ge=0, le=1)
38+
LOCUST_USERS: PositiveInt = Field(default=...)
39+
40+
PGHOST: str = Field(default="postgres")
41+
PGPASSWORD: str = Field(default="password")
42+
PGPORT: int = Field(default=5432)
43+
PGUSER: str = Field(default="postgres")
3544

3645
@field_validator("LOCUST_RUN_TIME", mode="before")
3746
@classmethod

0 commit comments

Comments
 (0)