locust 2.29.2.dev8__tar.gz → 2.29.2.dev15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/PKG-INFO +1 -1
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/test_data_management.py +36 -11
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/_version.py +2 -2
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/contrib/fasthttp.py +48 -13
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/event.py +32 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/runners.py +13 -22
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_runners.py +145 -11
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/PKG-INFO +1 -1
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.coveragerc +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.dockerignore +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.git-blame-ignore-revs +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.gitattributes +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/CONTRIBUTING.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/workflows/stale.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.github/workflows/tests.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.gitignore +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.pre-commit-config.yaml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.readthedocs.yaml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.vscode/extensions.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.vscode/launch.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.vscode/launch_locust.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/.vscode/settings.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/CHANGELOG.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/Dockerfile +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/LICENSE +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/MANIFEST.in +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/Makefile +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/README.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/SECURITY.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/Vagrantfile +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/benchmarks/dispatch.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/_static/theme-overrides.css +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/api.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/changelog.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/conf.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/configuration.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/custom-load-shape.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/developing-locust.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/extending-locust.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/extensions.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/faq.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/further-reading.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/history.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/extend_modern_web_ui_cache_stats.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/locust_workers.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/number_of_users.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/response_times.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/total_requests_per_second.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/userclass_picker_example.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/webui-running-statistics.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/images/webui-splash-screenshot.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/increase-performance.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/increasing-request-rate.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/index.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/installation.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/logging.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/quickstart.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/requirements.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/retrieving-stats.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/running-distributed.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/running-in-debugger.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/running-in-docker.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/running-without-web-ui.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/tasksets.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/testing-other-systems.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/use-as-lib.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/what-is-locust.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/docs/writing-a-locustfile.rst +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/add_command_line_argument.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/basic.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/browse_docs_sequence_test.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/browse_docs_test.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_messages.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_shape/double_wave.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_shape/stages.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_shape/staging_user_classes.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_shape/step_load.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_shape/wait_user_count.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_wait_function.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_xmlrpc_client/server.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/custom_xmlrpc_client/xmlrpc_locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/debugging.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/debugging_advanced.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dispatch_test_scripts/locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dispatch_test_scripts/run-disributed-headless.sh +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dispatch_test_scripts/run-disributed-web.sh +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dispatch_test_scripts/run-local-headless.sh +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dispatch_test_scripts/run-local-web.sh +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/docker-compose/docker-compose.yml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/dynamic_user_credentials.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/events.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/extend_web_ui.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/fast_http_locust.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/grpc_user.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/hello.proto +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/hello_pb2.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/hello_pb2_grpc.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/hello_server.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/grpc/locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/manual_stats_reporting.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/multiple_hosts.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/nested_inline_tasksets.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/rest.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/sdk_session_patching/session_patch_locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/semaphore_wait.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/stop_on_threshold.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/README.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/data_subnet.tf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/main.tf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/output.tf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/plan/basic.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/provisioner.tf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/terraform/aws/variables.tf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/use_as_lib.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/vagrant/README.md +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/vagrant/supervisord.conf +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/web_ui_auth.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/web_ui_cache_stats.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/examples/worker_index.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/generate_changelog.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/__main__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/argument_parser.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/clients.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/contrib/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/debug.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/dispatch.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/env.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/exception.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/html.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/input_events.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/log.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/main.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/py.typed +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/rpc/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/rpc/protocol.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/rpc/zmqrpc.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/shape.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/stats.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/fake_module1_for_env_test.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/fake_module2_for_env_test.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/mock_locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/mock_logging.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_debugging.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_dispatch.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_env.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_fasthttp.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_http.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_interruptable_task.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_load_locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_locust_class.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_log.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_main.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_old_wait_api.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_parser.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_sequential_taskset.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_stats.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_tags.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_taskratio.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_users.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_util.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_wait_time.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_web.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/test_zmqrpc.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/testcases.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/test/util.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/inspectuser.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/sequential_taskset.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/task.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/users.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/user/wait_time.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/__init__.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/cache.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/date.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/deprecation.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/exception_handler.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/load_locustfile.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/rounding.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/util/timespan.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/web.py +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/.eslintrc +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/.gitignore +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/.prettierrc +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/auth.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dev.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dist/assets/favicon.ico +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dist/assets/logo.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dist/auth.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dist/index.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/dist/report.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/index.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/package.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/public/assets/favicon.ico +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/public/assets/logo.png +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/public/report.html +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/App.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/App.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/DataTable/DataTable.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/DataTable/DataTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/ExceptionsTable/ExceptionsTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/FailuresTable/FailuresTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/FallbackRender/FallbackRender.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/FallbackRender/FallbackRender.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Form/Form.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Form/Select.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Form/tests/Form.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Form/tests/Select.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Footer/About.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Footer/Footer.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Layout.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Navbar/DarkLightToggle.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Navbar/Navbar.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Navbar/SwarmMonitor.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Layout/Navbar/SwarmMonitor.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LineChart/LineChart.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LineChart/LineChart.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LogViewer/LogViewer.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LogViewer/logUtils.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LogViewer/tests/LogViewer.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LogViewer/tests/useLogViewer.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/LogViewer/useLogViewer.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Modal/Modal.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Reports/Reports.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Reports/Reports.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/EditButton.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/NewTestButton.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/ResetButton.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/StateButtons.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/StopButton.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/tests/ResetButton.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/tests/StateButtons.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StateButtons/tests/StopButton.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/StatsTable/StatsTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmCharts/SwarmCharts.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/SwarmCustomParameters.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/SwarmEditForm.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/SwarmForm.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/SwarmUserClassPicker.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/tests/SwarmCustomParameters.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/tests/SwarmEditForm.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/tests/SwarmForm.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmForm/tests/SwarmUserClassPicker.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmRatios/SwarmRatios.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/SwarmRatios/SwarmRatios.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Table/Table.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Table/Table.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Tabs/Tabs.constants.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Tabs/Tabs.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/Tabs/Tabs.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/components/WorkersTable/WorkersTable.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/constants/auth.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/constants/logs.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/constants/swarm.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/constants/theme.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/global.d.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/tests/useNotifications.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/tests/useSelecteViewColumns.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/tests/useSortByField.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/tests/useSwarmUi.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/useInterval.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/useNotifications.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/useSelectViewColumns.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/useSortByField.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/hooks/useSwarmUi.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/index.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/Auth.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/Dashboard.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/HtmlReport.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/tests/Auth.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/tests/Dashboard.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/pages/tests/HtmlReport.test.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/api/swarm.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/hooks.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/logViewer.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/notification.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/root.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/swarm.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/tests/ui.slice.test.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/theme.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/ui.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/slice/url.slice.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/store.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/redux/utils.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/styles/theme.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/test/constants.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/test/mocks/statsRequest.mock.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/test/mocks/swarmState.mock.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/test/setup.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/test/testUtils.tsx +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/types/auth.types.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/types/swarm.types.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/types/tab.types.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/types/table.types.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/types/ui.types.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/array.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/date.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/number.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/object.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/string.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/tests/number.test.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/tests/object.test.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/tests/string.test.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/tests/url.test.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/src/utils/url.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/tsconfig.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/vite.config.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/vitest.config.ts +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust/webui/yarn.lock +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/SOURCES.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/dependency_links.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/entry_points.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/not-zip-safe +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/requires.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/locust.egg-info/top_level.txt +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/package.json +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/pyproject.toml +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/setup.cfg +0 -0
- {locust-2.29.2.dev8 → locust-2.29.2.dev15}/tox.ini +0 -0
@@ -6,6 +6,10 @@
|
|
6
6
|
# 3. Test start
|
7
7
|
# 4. User start
|
8
8
|
# 5. Inside a task
|
9
|
+
# M1. CPU & memory usage
|
10
|
+
# M2. master sent heartbeat to worker 1-N
|
11
|
+
# M3. worker 1-N received heartbeat from master
|
12
|
+
# (M* are repeated as long as locust is running)
|
9
13
|
# ...
|
10
14
|
# 6. Test run stopping
|
11
15
|
# 7. User stop
|
@@ -15,17 +19,21 @@
|
|
15
19
|
# 10. Locust quit
|
16
20
|
#
|
17
21
|
# try it out by running:
|
18
|
-
# locust -f test_data_management.py --headless -u 2 -t 5
|
22
|
+
# locust -f test_data_management.py --headless -u 2 -t 5 --processes 2
|
23
|
+
from __future__ import annotations
|
24
|
+
|
19
25
|
from locust import HttpUser, events, task
|
26
|
+
from locust.env import Environment
|
20
27
|
from locust.runners import MasterRunner
|
21
28
|
from locust.user.wait_time import constant
|
22
29
|
|
23
30
|
import datetime
|
31
|
+
from typing import Any
|
24
32
|
|
25
33
|
import requests
|
26
34
|
|
27
35
|
|
28
|
-
def timestring():
|
36
|
+
def timestring() -> str:
|
29
37
|
now = datetime.datetime.now()
|
30
38
|
return datetime.datetime.strftime(now, "%m:%S.%f")[:-5]
|
31
39
|
|
@@ -42,17 +50,17 @@ test_run_specific_data = None
|
|
42
50
|
|
43
51
|
|
44
52
|
@events.init.add_listener
|
45
|
-
def init(environment, **_kwargs):
|
53
|
+
def init(environment: Environment, **_kwargs: Any) -> None:
|
46
54
|
print("2. Initializing locust, happens after parsing the locustfile but before test start")
|
47
55
|
|
48
56
|
|
49
57
|
@events.quitting.add_listener
|
50
|
-
def quitting(environment, **_kwargs):
|
58
|
+
def quitting(environment: Environment, **_kwargs: Any) -> None:
|
51
59
|
print("9. locust is about to shut down")
|
52
60
|
|
53
61
|
|
54
62
|
@events.test_start.add_listener
|
55
|
-
def test_start(environment, **_kwargs):
|
63
|
+
def test_start(environment: Environment, **_kwargs) -> None:
|
56
64
|
# happens only once in headless runs, but can happen multiple times in web ui-runs
|
57
65
|
global test_run_specific_data
|
58
66
|
print("3. Starting test run")
|
@@ -64,18 +72,35 @@ def test_start(environment, **_kwargs):
|
|
64
72
|
).json()["data"]
|
65
73
|
|
66
74
|
|
75
|
+
@events.heartbeat_sent.add_listener
|
76
|
+
def heartbeat_sent(client_id: str, timestamp: float) -> None:
|
77
|
+
print(f"M2. master sent heartbeat to worker {client_id} at {datetime.datetime.fromtimestamp(timestamp)}")
|
78
|
+
|
79
|
+
|
80
|
+
@events.heartbeat_received.add_listener
|
81
|
+
def heartbeat_received(client_id: str, timestamp: float) -> None:
|
82
|
+
print(f"M3. worker {client_id} received heartbeat from master at {datetime.datetime.fromtimestamp(timestamp)}")
|
83
|
+
|
84
|
+
|
85
|
+
@events.usage_monitor.add_listener
|
86
|
+
def usage_monitor(environment: Environment, cpu_usage: float, memory_usage: int) -> None:
|
87
|
+
# convert from bytes to Mebibytes
|
88
|
+
memory_usage = memory_usage / 1024 / 1024
|
89
|
+
print(f"M1. {environment.runner.__class__.__name__}: cpu={cpu_usage}%, memory={memory_usage}M")
|
90
|
+
|
91
|
+
|
67
92
|
@events.quit.add_listener
|
68
|
-
def quit(exit_code, **kwargs):
|
93
|
+
def quit(exit_code: int, **kwargs: Any) -> None:
|
69
94
|
print(f"10. Locust has shut down with code {exit_code}")
|
70
95
|
|
71
96
|
|
72
97
|
@events.test_stopping.add_listener
|
73
|
-
def test_stopping(environment, **_kwargs):
|
98
|
+
def test_stopping(environment: Environment, **_kwargs: Any) -> None:
|
74
99
|
print("6. stopping test run")
|
75
100
|
|
76
101
|
|
77
102
|
@events.test_stop.add_listener
|
78
|
-
def test_stop(environment, **_kwargs):
|
103
|
+
def test_stop(environment: Environment, **_kwargs: Any) -> None:
|
79
104
|
print("8. test run stopped")
|
80
105
|
|
81
106
|
|
@@ -84,7 +109,7 @@ class MyUser(HttpUser):
|
|
84
109
|
wait_time = constant(180) # be nice to postman-echo
|
85
110
|
first_start = True
|
86
111
|
|
87
|
-
def on_start(self):
|
112
|
+
def on_start(self) -> None:
|
88
113
|
if MyUser.first_start:
|
89
114
|
MyUser.first_start = False
|
90
115
|
# This is useful for similar things as to test_start, but happens in the context of a User
|
@@ -101,7 +126,7 @@ class MyUser(HttpUser):
|
|
101
126
|
).json()["data"]
|
102
127
|
|
103
128
|
@task
|
104
|
-
def t(self):
|
129
|
+
def t(self) -> None:
|
105
130
|
self.client.get(f"/get?{global_test_data}")
|
106
131
|
self.client.get(f"/get?{test_run_specific_data}")
|
107
132
|
self.client.get(f"/get?{self.user_specific_testdata}")
|
@@ -114,6 +139,6 @@ class MyUser(HttpUser):
|
|
114
139
|
).json()["data"]
|
115
140
|
self.client.get(f"/get?{task_run_specific_testdata}")
|
116
141
|
|
117
|
-
def on_stop(self):
|
142
|
+
def on_stop(self) -> None:
|
118
143
|
# this is a good place to clean up/release any user-specific test data
|
119
144
|
print("7. a user was stopped")
|
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '2.29.2.
|
16
|
-
__version_tuple__ = version_tuple = (2, 29, 2, '
|
15
|
+
__version__ = version = '2.29.2.dev15'
|
16
|
+
__version_tuple__ = version_tuple = (2, 29, 2, 'dev15')
|
@@ -12,12 +12,11 @@ import socket
|
|
12
12
|
import time
|
13
13
|
import traceback
|
14
14
|
from base64 import b64encode
|
15
|
-
from collections.abc import Generator
|
16
15
|
from contextlib import contextmanager
|
17
16
|
from http.cookiejar import CookieJar
|
18
17
|
from json.decoder import JSONDecodeError
|
19
18
|
from ssl import SSLError
|
20
|
-
from typing import
|
19
|
+
from typing import TYPE_CHECKING, cast
|
21
20
|
from urllib.parse import urlparse, urlunparse
|
22
21
|
|
23
22
|
import gevent
|
@@ -32,6 +31,36 @@ from geventhttpclient.useragent import CompatRequest, CompatResponse, Connection
|
|
32
31
|
# borrow requests's content-type header parsing
|
33
32
|
from requests.utils import get_encoding_from_headers
|
34
33
|
|
34
|
+
if TYPE_CHECKING:
|
35
|
+
import sys
|
36
|
+
from collections.abc import Callable, Generator
|
37
|
+
from typing import TypedDict
|
38
|
+
|
39
|
+
if sys.version_info >= (3, 11):
|
40
|
+
from typing import Unpack
|
41
|
+
else:
|
42
|
+
from typing_extensions import Unpack
|
43
|
+
|
44
|
+
class PostKwargs(TypedDict, total=False):
|
45
|
+
name: str | None
|
46
|
+
catch_response: bool
|
47
|
+
stream: bool
|
48
|
+
headers: dict | None
|
49
|
+
auth: tuple[str | bytes, str | bytes] | None
|
50
|
+
allow_redirects: bool
|
51
|
+
context: dict
|
52
|
+
|
53
|
+
class PutKwargs(PostKwargs, total=False):
|
54
|
+
json: dict | None
|
55
|
+
|
56
|
+
class PatchKwargs(PostKwargs, total=False):
|
57
|
+
json: dict | None
|
58
|
+
|
59
|
+
class RESTKwargs(PostKwargs, total=False):
|
60
|
+
data: str | dict | None
|
61
|
+
json: dict | None
|
62
|
+
|
63
|
+
|
35
64
|
# Monkey patch geventhttpclient.useragent.CompatRequest so that Cookiejar works with Python >= 3.3
|
36
65
|
# More info: https://github.com/requests/requests/pull/871
|
37
66
|
CompatRequest.unverifiable = False
|
@@ -85,7 +114,7 @@ class FastHttpSession:
|
|
85
114
|
client_pool: HTTPClientPool | None = None,
|
86
115
|
ssl_context_factory: Callable | None = None,
|
87
116
|
**kwargs,
|
88
|
-
):
|
117
|
+
) -> None:
|
89
118
|
self.environment = environment
|
90
119
|
self.base_url = base_url
|
91
120
|
self.cookiejar = CookieJar()
|
@@ -117,14 +146,14 @@ class FastHttpSession:
|
|
117
146
|
# store authentication header (we construct this by using _basic_auth_str() function from requests.auth)
|
118
147
|
self.auth_header = _construct_basic_auth_str(parsed_url.username, parsed_url.password)
|
119
148
|
|
120
|
-
def _build_url(self, path):
|
149
|
+
def _build_url(self, path: str) -> str:
|
121
150
|
"""prepend url with hostname unless it's already an absolute URL"""
|
122
151
|
if absolute_http_url_regexp.match(path):
|
123
152
|
return path
|
124
153
|
else:
|
125
154
|
return f"{self.base_url}{path}"
|
126
155
|
|
127
|
-
def _send_request_safe_mode(self, method, url, **kwargs):
|
156
|
+
def _send_request_safe_mode(self, method: str, url: str, **kwargs):
|
128
157
|
"""
|
129
158
|
Send an HTTP request, and catch any exception that might occur due to either
|
130
159
|
connection problems, or invalid HTTP status codes
|
@@ -155,7 +184,7 @@ class FastHttpSession:
|
|
155
184
|
catch_response: bool = False,
|
156
185
|
stream: bool = False,
|
157
186
|
headers: dict | None = None,
|
158
|
-
auth=None,
|
187
|
+
auth: tuple[str | bytes, str | bytes] | None = None,
|
159
188
|
json: dict | None = None,
|
160
189
|
allow_redirects: bool = True,
|
161
190
|
context: dict = {},
|
@@ -264,31 +293,37 @@ class FastHttpSession:
|
|
264
293
|
self.environment.events.request.fire(**request_meta)
|
265
294
|
return response
|
266
295
|
|
267
|
-
def delete(self, url, **kwargs):
|
296
|
+
def delete(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
|
268
297
|
"""Sends a DELETE request"""
|
269
298
|
return self.request("DELETE", url, **kwargs)
|
270
299
|
|
271
|
-
def get(self, url, **kwargs):
|
300
|
+
def get(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
|
272
301
|
"""Sends a GET request"""
|
273
302
|
return self.request("GET", url, **kwargs)
|
274
303
|
|
275
|
-
def head(self, url, **kwargs):
|
304
|
+
def head(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
|
276
305
|
"""Sends a HEAD request"""
|
277
306
|
return self.request("HEAD", url, **kwargs)
|
278
307
|
|
279
|
-
def options(self, url, **kwargs):
|
308
|
+
def options(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
|
280
309
|
"""Sends a OPTIONS request"""
|
281
310
|
return self.request("OPTIONS", url, **kwargs)
|
282
311
|
|
283
|
-
def patch(
|
312
|
+
def patch(
|
313
|
+
self, url: str, data: str | dict | None = None, **kwargs: Unpack[PatchKwargs]
|
314
|
+
) -> ResponseContextManager | FastResponse:
|
284
315
|
"""Sends a PATCH request"""
|
285
316
|
return self.request("PATCH", url, data=data, **kwargs)
|
286
317
|
|
287
|
-
def post(
|
318
|
+
def post(
|
319
|
+
self, url: str, data: str | dict | None = None, json: dict | None = None, **kwargs: Unpack[PostKwargs]
|
320
|
+
) -> ResponseContextManager | FastResponse:
|
288
321
|
"""Sends a POST request"""
|
289
322
|
return self.request("POST", url, data=data, json=json, **kwargs)
|
290
323
|
|
291
|
-
def put(
|
324
|
+
def put(
|
325
|
+
self, url: str, data: str | dict | None = None, **kwargs: Unpack[PutKwargs]
|
326
|
+
) -> ResponseContextManager | FastResponse:
|
292
327
|
"""Sends a PUT request"""
|
293
328
|
return self.request("PUT", url, data=data, **kwargs)
|
294
329
|
|
@@ -235,6 +235,38 @@ class Events:
|
|
235
235
|
Fired when the CPU usage exceeds runners.CPU_WARNING_THRESHOLD (90% by default)
|
236
236
|
"""
|
237
237
|
|
238
|
+
heartbeat_sent: EventHook
|
239
|
+
"""
|
240
|
+
Fired when a heartbeat is sent by master to a worker.
|
241
|
+
|
242
|
+
Event arguments:
|
243
|
+
|
244
|
+
:param client_id: worker client id
|
245
|
+
:param timestamp: time in seconds since the epoch (float) when the event occured
|
246
|
+
"""
|
247
|
+
|
248
|
+
heartbeat_received: EventHook
|
249
|
+
"""
|
250
|
+
Fired when a heartbeat is received by a worker from master.
|
251
|
+
|
252
|
+
Event arguments:
|
253
|
+
|
254
|
+
:param client_id: worker client id
|
255
|
+
:param timestamp: time in seconds since the epoch (float) when the event occured
|
256
|
+
"""
|
257
|
+
|
258
|
+
usage_monitor: EventHook
|
259
|
+
"""
|
260
|
+
Fired every runners.CPU_MONITOR_INTERVAL (5.0 seconds by default) with information about
|
261
|
+
current CPU and memory usage.
|
262
|
+
|
263
|
+
Event arguments:
|
264
|
+
|
265
|
+
:param environment: locust environment
|
266
|
+
:param cpu_usage: current CPU usage in percent
|
267
|
+
:param memory_usage: current memory usage (RSS) in bytes
|
268
|
+
"""
|
269
|
+
|
238
270
|
def __init__(self):
|
239
271
|
# For backward compatibility use also values of class attributes
|
240
272
|
for name, value in vars(type(self)).items():
|
@@ -15,19 +15,9 @@ import traceback
|
|
15
15
|
from abc import abstractmethod
|
16
16
|
from collections import defaultdict
|
17
17
|
from collections.abc import Iterator, MutableMapping, ValuesView
|
18
|
-
from operator import
|
19
|
-
itemgetter,
|
20
|
-
methodcaller,
|
21
|
-
)
|
18
|
+
from operator import itemgetter, methodcaller
|
22
19
|
from types import TracebackType
|
23
|
-
from typing import
|
24
|
-
TYPE_CHECKING,
|
25
|
-
Any,
|
26
|
-
Callable,
|
27
|
-
NoReturn,
|
28
|
-
TypedDict,
|
29
|
-
cast,
|
30
|
-
)
|
20
|
+
from typing import TYPE_CHECKING, Any, Callable, NoReturn, TypedDict, cast
|
31
21
|
from uuid import uuid4
|
32
22
|
|
33
23
|
import gevent
|
@@ -40,15 +30,8 @@ from . import argument_parser
|
|
40
30
|
from .dispatch import UsersDispatcher
|
41
31
|
from .exception import RPCError, RPCReceiveError, RPCSendError
|
42
32
|
from .log import get_logs, greenlet_exception_logger
|
43
|
-
from .rpc import
|
44
|
-
|
45
|
-
rpc,
|
46
|
-
)
|
47
|
-
from .stats import (
|
48
|
-
RequestStats,
|
49
|
-
StatsError,
|
50
|
-
setup_distributed_stats_event_listeners,
|
51
|
-
)
|
33
|
+
from .rpc import Message, rpc
|
34
|
+
from .stats import RequestStats, StatsError, setup_distributed_stats_event_listeners
|
52
35
|
|
53
36
|
if TYPE_CHECKING:
|
54
37
|
from . import User
|
@@ -106,7 +89,7 @@ class Runner:
|
|
106
89
|
self.spawning_greenlet: gevent.Greenlet | None = None
|
107
90
|
self.shape_greenlet: gevent.Greenlet | None = None
|
108
91
|
self.shape_last_tick: tuple[int, float] | tuple[int, float, list[type[User]] | None] | None = None
|
109
|
-
self.current_cpu_usage:
|
92
|
+
self.current_cpu_usage: float = 0.0
|
110
93
|
self.cpu_warning_emitted: bool = False
|
111
94
|
self.worker_cpu_warning_emitted: bool = False
|
112
95
|
self.current_memory_usage: int = 0
|
@@ -308,6 +291,10 @@ class Runner:
|
|
308
291
|
f"CPU usage above {CPU_WARNING_THRESHOLD}%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines"
|
309
292
|
)
|
310
293
|
self.cpu_warning_emitted = True
|
294
|
+
|
295
|
+
self.environment.events.usage_monitor.fire(
|
296
|
+
environment=self.environment, cpu_usage=self.current_cpu_usage, memory_usage=self.current_memory_usage
|
297
|
+
)
|
311
298
|
gevent.sleep(CPU_MONITOR_INTERVAL)
|
312
299
|
|
313
300
|
@abstractmethod
|
@@ -1102,6 +1089,7 @@ class MasterRunner(DistributedRunner):
|
|
1102
1089
|
)
|
1103
1090
|
if "current_memory_usage" in msg.data:
|
1104
1091
|
c.memory_usage = msg.data["current_memory_usage"]
|
1092
|
+
self.environment.events.heartbeat_sent.fire(client_id=msg.node_id, timestamp=time.time())
|
1105
1093
|
self.server.send_to_client(Message("heartbeat", None, msg.node_id))
|
1106
1094
|
else:
|
1107
1095
|
logging.debug(f"Got heartbeat message from unknown worker {msg.node_id}")
|
@@ -1399,6 +1387,9 @@ class WorkerRunner(DistributedRunner):
|
|
1399
1387
|
self.reset_connection()
|
1400
1388
|
elif msg.type == "heartbeat":
|
1401
1389
|
self.last_heartbeat_timestamp = time.time()
|
1390
|
+
self.environment.events.heartbeat_received.fire(
|
1391
|
+
client_id=msg.node_id, timestamp=self.last_heartbeat_timestamp
|
1392
|
+
)
|
1402
1393
|
elif msg.type == "update_user_class":
|
1403
1394
|
self.environment.update_user_class(msg.data)
|
1404
1395
|
elif msg.type == "spawning_complete":
|
@@ -1,12 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import locust
|
4
|
-
from locust import
|
5
|
-
LoadTestShape,
|
6
|
-
__version__,
|
7
|
-
constant,
|
8
|
-
runners,
|
9
|
-
)
|
4
|
+
from locust import LoadTestShape, __version__, constant, runners
|
10
5
|
from locust.argument_parser import parse_options
|
11
6
|
from locust.dispatch import UsersDispatcher
|
12
7
|
from locust.env import Environment
|
@@ -26,11 +21,7 @@ from locust.runners import (
|
|
26
21
|
WorkerRunner,
|
27
22
|
)
|
28
23
|
from locust.stats import RequestStats
|
29
|
-
from locust.user import
|
30
|
-
TaskSet,
|
31
|
-
User,
|
32
|
-
task,
|
33
|
-
)
|
24
|
+
from locust.user import TaskSet, User, task
|
34
25
|
|
35
26
|
import json
|
36
27
|
import logging
|
@@ -2136,6 +2127,149 @@ class TestMasterWorkerRunners(LocustTestCase):
|
|
2136
2127
|
|
2137
2128
|
self.assertEqual(test_start_exec_count, 1)
|
2138
2129
|
|
2130
|
+
def test_heartbeat_event(self) -> None:
|
2131
|
+
"""
|
2132
|
+
Tests that heartbeat event is fired during a test
|
2133
|
+
"""
|
2134
|
+
|
2135
|
+
class TestUser(User):
|
2136
|
+
wait_time = constant(0.1)
|
2137
|
+
|
2138
|
+
@task
|
2139
|
+
def noop(self) -> None:
|
2140
|
+
pass
|
2141
|
+
|
2142
|
+
with mock.patch("locust.runners.HEARTBEAT_INTERVAL", new=1):
|
2143
|
+
# start a Master runner
|
2144
|
+
master_env = Environment(user_classes=[TestUser])
|
2145
|
+
worker_connect_events = []
|
2146
|
+
timestamp_start: list[float] = [time.time() + 3600.0]
|
2147
|
+
|
2148
|
+
def on_connect(client_id: str) -> None:
|
2149
|
+
worker_connect_events.append(client_id)
|
2150
|
+
timestamp_start[0] = time.time()
|
2151
|
+
|
2152
|
+
master_env.events.worker_connect.add_listener(on_connect)
|
2153
|
+
master = master_env.create_master_runner("*", 0)
|
2154
|
+
sleep(0)
|
2155
|
+
worker_env = Environment(user_classes=[TestUser])
|
2156
|
+
worker: WorkerRunner = worker_env.create_worker_runner("127.0.0.1", master.server.port)
|
2157
|
+
|
2158
|
+
with (
|
2159
|
+
mock.patch.object(
|
2160
|
+
worker.environment.events.heartbeat_received,
|
2161
|
+
"fire",
|
2162
|
+
wraps=worker.environment.events.heartbeat_received.fire,
|
2163
|
+
) as worker_heartbeat_received_mock,
|
2164
|
+
mock.patch.object(
|
2165
|
+
master.environment.events.heartbeat_sent,
|
2166
|
+
"fire",
|
2167
|
+
wraps=master.environment.events.heartbeat_sent.fire,
|
2168
|
+
) as master_heartbeat_sent_mock,
|
2169
|
+
):
|
2170
|
+
# give workers time to connect
|
2171
|
+
sleep(0.1)
|
2172
|
+
# issue start command that should trigger TestUsers to be spawned in the Workers
|
2173
|
+
master.start(2, spawn_rate=2)
|
2174
|
+
sleep(0.1)
|
2175
|
+
# check that worker nodes have started locusts
|
2176
|
+
self.assertEqual(2, worker.user_count)
|
2177
|
+
|
2178
|
+
# give time for nodes to send and receive 5 heartbeats, HEARTBEAT_INTERVAL mocked to 1 second, so
|
2179
|
+
# sleep 5 seconds - 1 second that represents the overhead from connecting
|
2180
|
+
sleep(5 - 1)
|
2181
|
+
master.quit()
|
2182
|
+
|
2183
|
+
# make sure users are killed
|
2184
|
+
self.assertEqual(0, worker.user_count)
|
2185
|
+
# make sure events happened correctly
|
2186
|
+
self.assertIn(worker.client_id, worker_connect_events)
|
2187
|
+
|
2188
|
+
timestamp_stop = time.time()
|
2189
|
+
|
2190
|
+
self.assertEqual(worker_heartbeat_received_mock.call_count, 5)
|
2191
|
+
self.assertEqual(master_heartbeat_sent_mock.call_count, 5)
|
2192
|
+
|
2193
|
+
for call_args, call_kwargs in [
|
2194
|
+
*worker_heartbeat_received_mock.call_args_list,
|
2195
|
+
*master_heartbeat_sent_mock.call_args_list,
|
2196
|
+
]:
|
2197
|
+
self.assertEqual(call_args, ()) # args
|
2198
|
+
self.assertEqual(call_kwargs, {"client_id": worker.client_id, "timestamp": mock.ANY}) # kwargs
|
2199
|
+
self.assertGreaterEqual(call_kwargs["timestamp"], timestamp_start[0])
|
2200
|
+
self.assertLessEqual(call_kwargs["timestamp"], timestamp_stop)
|
2201
|
+
|
2202
|
+
def test_usage_monitor_event(self) -> None:
|
2203
|
+
"""
|
2204
|
+
Tests that usage_monitor event is fired during a test
|
2205
|
+
"""
|
2206
|
+
|
2207
|
+
class TestUser(User):
|
2208
|
+
wait_time = constant(0.1)
|
2209
|
+
|
2210
|
+
@task
|
2211
|
+
def noop(self) -> None:
|
2212
|
+
pass
|
2213
|
+
|
2214
|
+
with mock.patch("locust.runners.CPU_MONITOR_INTERVAL", new=1):
|
2215
|
+
# start a Master runner
|
2216
|
+
master_env = Environment(user_classes=[TestUser])
|
2217
|
+
worker_connect_events = []
|
2218
|
+
|
2219
|
+
def on_connect(client_id: str) -> None:
|
2220
|
+
worker_connect_events.append(client_id)
|
2221
|
+
|
2222
|
+
master_env.events.worker_connect.add_listener(on_connect)
|
2223
|
+
master = master_env.create_master_runner("*", 0)
|
2224
|
+
sleep(0)
|
2225
|
+
worker_env = Environment(user_classes=[TestUser])
|
2226
|
+
worker: WorkerRunner = worker_env.create_worker_runner("127.0.0.1", master.server.port)
|
2227
|
+
|
2228
|
+
with (
|
2229
|
+
mock.patch.object(
|
2230
|
+
worker.environment.events.usage_monitor, "fire", wraps=worker.environment.events.usage_monitor.fire
|
2231
|
+
) as worker_usage_monitor_mock,
|
2232
|
+
mock.patch.object(
|
2233
|
+
master.environment.events.usage_monitor, "fire", wraps=master.environment.events.usage_monitor.fire
|
2234
|
+
) as master_usage_monitor_mock,
|
2235
|
+
):
|
2236
|
+
# give workers time to connect
|
2237
|
+
sleep(0.1)
|
2238
|
+
# issue start command that should trigger TestUsers to be spawned in the Workers
|
2239
|
+
master.start(2, spawn_rate=2)
|
2240
|
+
sleep(0.1)
|
2241
|
+
# check that worker nodes have started locusts
|
2242
|
+
self.assertEqual(2, worker.user_count)
|
2243
|
+
|
2244
|
+
# give time for nodes to send 5 usage_monitor events, CPU_MONITOR_INTERVAL mocked to 1 second, so
|
2245
|
+
# sleep 5 seconds
|
2246
|
+
sleep(5)
|
2247
|
+
master.quit()
|
2248
|
+
|
2249
|
+
# make sure users are killed
|
2250
|
+
self.assertEqual(0, worker.user_count)
|
2251
|
+
# make sure events happened correctly
|
2252
|
+
self.assertIn(worker.client_id, worker_connect_events)
|
2253
|
+
|
2254
|
+
self.assertEqual(worker_usage_monitor_mock.call_count, 5)
|
2255
|
+
self.assertEqual(master_usage_monitor_mock.call_count, 5)
|
2256
|
+
|
2257
|
+
for call_args, call_kwargs in master_usage_monitor_mock:
|
2258
|
+
self.assertEqual(call_args, ()) # args
|
2259
|
+
self.assertEqual(
|
2260
|
+
call_kwargs, {"environment": master_env, "cpu_usage": mock.ANY, "memory_usage": mock.ANY}
|
2261
|
+
) # kwargs
|
2262
|
+
self.assertTrue(isinstance(call_kwargs["cpu_usage"], float))
|
2263
|
+
self.assertTrue(isinstance(call_kwargs["memory_usage"], int))
|
2264
|
+
|
2265
|
+
for call_args, call_kwargs in worker_usage_monitor_mock:
|
2266
|
+
self.assertEqual(call_args, ()) # args
|
2267
|
+
self.assertEqual(
|
2268
|
+
call_kwargs, {"environment": worker_env, "cpu_usage": mock.ANY, "memory_usage": mock.ANY}
|
2269
|
+
) # kwargs
|
2270
|
+
self.assertTrue(isinstance(call_kwargs["cpu_usage"], float))
|
2271
|
+
self.assertTrue(isinstance(call_kwargs["memory_usage"], int))
|
2272
|
+
|
2139
2273
|
|
2140
2274
|
class TestMasterRunner(LocustRunnerTestCase):
|
2141
2275
|
def setUp(self):
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|