diff --git a/tests/performance/locustfiles/deployment_max_rps_single_endpoint.py b/tests/performance/locustfiles/deployment_max_rps_single_endpoint.py index e457d3c00d13..74de2c18417b 100644 --- a/tests/performance/locustfiles/deployment_max_rps_single_endpoint.py +++ b/tests/performance/locustfiles/deployment_max_rps_single_endpoint.py @@ -12,6 +12,7 @@ import json from collections.abc import Callable +import jsf from common.base_user import OsparcWebUserBase from locust import events, task from locust.argument_parser import LocustArgumentParser @@ -36,7 +37,19 @@ def _(parser: LocustArgumentParser) -> None: "--body", type=str, default="", - help="The optional HTTP body as json string", + help="Optional HTTP body as json string", + ) + parser.add_argument( + "--body-json-schema", + type=str, + default="", + help="Optional JSON schema for the request body. If specified, the request data will be randomly generated from this schema.", + ) + parser.add_argument( + "--headers", + type=str, + default="", + help="Optional HTTP headers as json string", ) @@ -52,4 +65,11 @@ def get_endpoint(self) -> None: kwargs = {} if len(self.environment.parsed_options.body) > 0: kwargs["json"] = json.loads(self.environment.parsed_options.body) + if len(self.environment.parsed_options.body_json_schema) > 0: + faker = jsf.JSF( + json.loads(self.environment.parsed_options.body_json_schema) + ) + kwargs["json"] = faker.generate() + if len(self.environment.parsed_options.headers) > 0: + kwargs["headers"] = json.loads(self.environment.parsed_options.headers) method(self.environment.parsed_options.endpoint, **kwargs) diff --git a/tests/performance/requirements/_test.in b/tests/performance/requirements/_test.in index c2ffb26a7f91..2dd40a77bd31 100644 --- a/tests/performance/requirements/_test.in +++ b/tests/performance/requirements/_test.in @@ -1,3 +1,4 @@ +jsf locust locust-plugins[dashboards] pydantic diff --git a/tests/performance/requirements/_test.txt b/tests/performance/requirements/_test.txt index c5bafb89bc90..d0cd5d6b9ec8 100644 --- a/tests/performance/requirements/_test.txt +++ b/tests/performance/requirements/_test.txt @@ -1,5 +1,9 @@ annotated-types==0.7.0 # via pydantic +attrs==25.3.0 + # via + # jsonschema + # referencing bidict==0.23.1 # via python-socketio blinker==1.9.0 @@ -18,6 +22,8 @@ configargparse==1.7.1 # via # locust # locust-cloud +faker==37.6.0 + # via jsf flask==3.1.1 # via # flask-cors @@ -44,6 +50,12 @@ itsdangerous==2.2.0 # via flask jinja2==3.1.6 # via flask +jsf==0.11.2 + # via -r requirements/_test.in +jsonschema==4.25.1 + # via jsf +jsonschema-specifications==2025.4.1 + # via jsonschema locust==2.37.5 # via # -r requirements/_test.in @@ -70,6 +82,7 @@ psycopg2-binary==2.9.10 pydantic==2.11.7 # via # -r requirements/_test.in + # jsf # pydantic-settings pydantic-core==2.33.2 # via pydantic @@ -83,10 +96,21 @@ python-socketio==5.13.0 # via locust-cloud pyzmq==26.4.0 # via locust +referencing==0.36.2 + # via + # jsonschema + # jsonschema-specifications requests==2.32.4 # via # locust # python-socketio + # smart-open +rpds-py==0.27.1 + # via + # jsonschema + # referencing +rstr==3.2.2 + # via jsf setuptools==80.9.0 # via # locust @@ -94,18 +118,24 @@ setuptools==80.9.0 # zope-interface simple-websocket==1.1.0 # via python-engineio +smart-open==7.3.0.post1 + # via jsf tenacity==9.1.2 # via -r requirements/_test.in typing-extensions==4.14.1 # via + # jsf # locust-plugins # pydantic # pydantic-core + # referencing # typing-inspection typing-inspection==0.4.1 # via # pydantic # pydantic-settings +tzdata==2025.2 + # via faker urllib3==2.5.0 # via # geventhttpclient @@ -118,6 +148,8 @@ werkzeug==3.1.3 # flask-cors # flask-login # locust +wrapt==1.17.3 + # via smart-open wsproto==1.2.0 # via simple-websocket zope-event==5.0