Skip to content

Commit b1dc11b

Browse files
authored
Merge branch 'master' into fix/test-settings
2 parents c955230 + ec1e84e commit b1dc11b

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

tests/performance/Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export ENV_FILE
1212
NETWORK_NAME=dashboards_timenet
1313

1414
# UTILS
15-
get_my_ip := $(shell (hostname --all-ip-addresses || hostname -i) 2>/dev/null | cut --delimiter=" " --fields=1)
15+
# NOTE: keep short arguments for `cut` so it works in both BusyBox (alpine) AND Ubuntu
16+
get_my_ip := $(shell (hostname --all-ip-addresses || hostname -i) 2>/dev/null | cut -d " " -f 1)
1617

1718
# Check that given variables are set and all have non-empty values,
1819
# die with an error otherwise.
@@ -28,6 +29,7 @@ __check_defined = \
2829
$(error Undefined $1$(if $2, ($2))))
2930

3031

32+
3133
.PHONY: build
3234
build: ## builds distributed osparc locust docker image
3335
docker \
@@ -42,6 +44,8 @@ build: ## builds distributed osparc locust docker image
4244
push:
4345
docker push itisfoundation/locust:$(LOCUST_VERSION)
4446

47+
48+
4549
.PHONY: down
4650
down: ## stops and removes osparc locust containers
4751
docker compose --file docker-compose.yml down
@@ -55,6 +59,8 @@ test: ## runs osparc locust. Locust and test configuration are specified in ENV_
5559
fi
5660
docker compose --file docker-compose.yml up --scale worker=4 --exit-code-from=master
5761

62+
63+
5864
.PHONY: dashboards-up dashboards-down
5965

6066
dashboards-up: ## Create Grafana dashboard for inspecting locust results. See dashboard on localhost:3000
@@ -68,6 +74,8 @@ dashboards-up: ## Create Grafana dashboard for inspecting locust results. See da
6874
dashboards-down:
6975
@locust-compose down
7076

77+
78+
7179
.PHONY: install-ci install-dev
7280

7381
install-dev:
@@ -80,4 +88,4 @@ install-ci:
8088
.PHONY: config
8189
config:
8290
@$(call check_defined, input, please define inputs when calling $@ - e.g. ```make $@ input="--help"```)
83-
@uv run locust_settings.py $(input) | tee .env
91+
@uv run locust_settings.py $(input) | tee "${ENV_FILE}"

tests/performance/locust_files/platform_ping_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
assert locust_plugins # nosec
2020

2121

22-
class LocustAuth(BaseSettings):
22+
class MonitoringBasicAuth(BaseSettings):
2323
SC_USER_NAME: str = Field(default=..., examples=["<your username>"])
2424
SC_PASSWORD: str = Field(default=..., examples=["<your password>"])
2525

2626

2727
class WebApiUser(FastHttpUser):
2828
def __init__(self, *args, **kwargs):
2929
super().__init__(*args, **kwargs)
30-
_auth = LocustAuth()
30+
_auth = MonitoringBasicAuth()
3131
self.auth = (
3232
_auth.SC_USER_NAME,
3333
_auth.SC_PASSWORD,

tests/performance/locust_settings.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
# /// script
2+
# requires-python = ">=3.11"
3+
# dependencies = [
4+
# "parse",
5+
# "pydantic",
6+
# "pydantic-settings",
7+
# ]
8+
# ///
19
# pylint: disable=unused-argument
210
# pylint: disable=no-self-use
311
# pylint: disable=no-name-in-module
412

13+
import importlib.util
14+
import inspect
515
import json
616
from datetime import timedelta
717
from pathlib import Path
18+
from types import ModuleType
819
from typing import Final
920

1021
from parse import Result, parse
@@ -26,6 +37,37 @@
2637
assert _LOCUST_FILES_DIR.is_dir()
2738

2839

40+
def _check_load_and_instantiate_settings_classes(file_path: str):
41+
module_name = Path(file_path).stem
42+
spec = importlib.util.spec_from_file_location(module_name, file_path)
43+
if spec is None or spec.loader is None:
44+
msg = f"Invalid {file_path=}"
45+
raise ValueError(msg)
46+
47+
module: ModuleType = importlib.util.module_from_spec(spec)
48+
49+
# Execute the module in its own namespace
50+
try:
51+
spec.loader.exec_module(module)
52+
except Exception as e:
53+
msg = f"Failed to load module {module_name} from {file_path}"
54+
raise ValueError(msg) from e
55+
56+
# Filter subclasses of BaseSettings
57+
settings_classes = [
58+
obj
59+
for _, obj in inspect.getmembers(module, inspect.isclass)
60+
if issubclass(obj, BaseSettings) and obj is not BaseSettings
61+
]
62+
63+
for settings_class in settings_classes:
64+
try:
65+
settings_class()
66+
except Exception as e:
67+
msg = f"Missing env vars for {settings_class.__name__} in {file_path=}: {e}"
68+
raise ValueError(msg) from e
69+
70+
2971
class LocustSettings(BaseSettings):
3072
model_config = SettingsConfigDict(cli_parse_args=True)
3173

@@ -44,8 +86,8 @@ class LocustSettings(BaseSettings):
4486
LOCUST_RUN_TIME: timedelta
4587
LOCUST_SPAWN_RATE: PositiveInt = Field(default=20)
4688

47-
# Options for Timescale + Grafana Dashboards
48-
# SEE https://github.com/SvenskaSpel/locust-plugins/blob/master/locust_plugins/timescale/
89+
# Timescale: Log and graph results using TimescaleDB and Grafana dashboards
90+
# SEE https://github.com/SvenskaSpel/locust-plugins/tree/master/locust_plugins/dashboards
4991
#
5092
LOCUST_TIMESCALE: NonNegativeInt = Field(
5193
default=1,
@@ -87,6 +129,10 @@ def _validate_locust_file(cls, v: Path) -> Path:
87129
if not v.is_relative_to(_LOCUST_FILES_DIR):
88130
msg = f"{v} must be a test file relative to {_LOCUST_FILES_DIR}"
89131
raise ValueError(msg)
132+
133+
# NOTE: CHECK that all the env-vars are defined for this test
134+
# _check_load_and_instantiate_settings_classes(f"{v}")
135+
90136
return v.relative_to(_TEST_DIR)
91137

92138
@field_serializer("LOCUST_RUN_TIME")

0 commit comments

Comments
 (0)