locust 2.22.1.dev45__tar.gz → 2.22.1.dev67__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.
Files changed (343) hide show
  1. {locust-2.22.1.dev45/locust.egg-info → locust-2.22.1.dev67}/PKG-INFO +1 -1
  2. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/running-distributed.rst +6 -3
  3. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/_version.py +2 -2
  4. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/argument_parser.py +79 -1
  5. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/runners.py +34 -0
  6. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_main.py +177 -8
  7. locust-2.22.1.dev45/locust/webui/dist/assets/index-e80c0bba.js → locust-2.22.1.dev67/locust/webui/dist/assets/index-5730ea01.js +48 -49
  8. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dist/auth.html +1 -1
  9. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dist/index.html +1 -1
  10. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/FailuresTable/FailuresTable.tsx +1 -15
  11. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.tsx +3 -1
  12. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StatsTable/StatsTable.tsx +1 -11
  13. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Table/Table.test.tsx +1 -12
  14. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Table/Table.tsx +11 -5
  15. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/WorkersTable/WorkersTable.tsx +1 -15
  16. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/tests/useSortByField.test.tsx +2 -2
  17. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/useSortByField.ts +24 -22
  18. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/vite.config.ts +1 -1
  19. {locust-2.22.1.dev45 → locust-2.22.1.dev67/locust.egg-info}/PKG-INFO +1 -1
  20. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/SOURCES.txt +1 -3
  21. locust-2.22.1.dev45/locust/webui/dist/assets/auth-0ef39448.js.map +0 -1
  22. locust-2.22.1.dev45/locust/webui/dist/assets/index-e80c0bba.js.map +0 -1
  23. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.coveragerc +0 -0
  24. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.dockerignore +0 -0
  25. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.git-blame-ignore-revs +0 -0
  26. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.gitattributes +0 -0
  27. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/CONTRIBUTING.md +0 -0
  28. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  29. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  30. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  31. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/workflows/stale.yml +0 -0
  32. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.github/workflows/tests.yml +0 -0
  33. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.gitignore +0 -0
  34. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.readthedocs.yaml +0 -0
  35. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.vscode/extensions.json +0 -0
  36. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.vscode/launch.json +0 -0
  37. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.vscode/launch_locust.json +0 -0
  38. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/.vscode/settings.json +0 -0
  39. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/CHANGELOG.md +0 -0
  40. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/Dockerfile +0 -0
  41. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/LICENSE +0 -0
  42. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/MANIFEST.in +0 -0
  43. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/Makefile +0 -0
  44. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/README +0 -0
  45. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/README.md +0 -0
  46. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/SECURITY.md +0 -0
  47. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/Vagrantfile +0 -0
  48. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/benchmarks/dispatch.py +0 -0
  49. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/_static/theme-overrides.css +0 -0
  50. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/api.rst +0 -0
  51. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/changelog.rst +0 -0
  52. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/conf.py +0 -0
  53. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/configuration.rst +0 -0
  54. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/custom-load-shape.rst +0 -0
  55. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/developing-locust.rst +0 -0
  56. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/extending-locust.rst +0 -0
  57. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/further-reading.rst +0 -0
  58. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/history.rst +0 -0
  59. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/locust_workers.png +0 -0
  60. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/number_of_users.png +0 -0
  61. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/response_times.png +0 -0
  62. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/total_requests_per_second.png +0 -0
  63. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/userclass_picker_example.png +0 -0
  64. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/webui-running-statistics.png +0 -0
  65. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/images/webui-splash-screenshot.png +0 -0
  66. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/increase-performance.rst +0 -0
  67. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/index.rst +0 -0
  68. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/installation.rst +0 -0
  69. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/logging.rst +0 -0
  70. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/quickstart.rst +0 -0
  71. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/requirements.txt +0 -0
  72. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/retrieving-stats.rst +0 -0
  73. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/running-cloud-integration.rst +0 -0
  74. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/running-in-debugger.rst +0 -0
  75. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/running-in-docker.rst +0 -0
  76. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/running-without-web-ui.rst +0 -0
  77. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/tasksets.rst +0 -0
  78. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/testing-other-systems.rst +0 -0
  79. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/use-as-lib.rst +0 -0
  80. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/what-is-locust.rst +0 -0
  81. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/docs/writing-a-locustfile.rst +0 -0
  82. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/add_command_line_argument.py +0 -0
  83. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/basic.py +0 -0
  84. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/browse_docs_sequence_test.py +0 -0
  85. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/browse_docs_test.py +0 -0
  86. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_messages.py +0 -0
  87. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_shape/double_wave.py +0 -0
  88. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_shape/stages.py +0 -0
  89. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_shape/staging_user_classes.py +0 -0
  90. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_shape/step_load.py +0 -0
  91. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_shape/wait_user_count.py +0 -0
  92. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_wait_function.py +0 -0
  93. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_xmlrpc_client/server.py +0 -0
  94. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/custom_xmlrpc_client/xmlrpc_locustfile.py +0 -0
  95. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/debugging.py +0 -0
  96. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/debugging_advanced.py +0 -0
  97. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/docker-compose/docker-compose.yml +0 -0
  98. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/dynamic_user_credentials.py +0 -0
  99. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/events.py +0 -0
  100. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/extend_modern_web_ui.py +0 -0
  101. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/extend_web_ui/extend.py +0 -0
  102. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/extend_web_ui/static/custom-stats-table.css +0 -0
  103. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/extend_web_ui/static/extend.js +0 -0
  104. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/extend_web_ui/templates/extend.html +0 -0
  105. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/fast_http_locust.py +0 -0
  106. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/grpc_user.py +0 -0
  107. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/hello.proto +0 -0
  108. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/hello_pb2.py +0 -0
  109. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/hello_pb2_grpc.py +0 -0
  110. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/hello_server.py +0 -0
  111. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/grpc/locustfile.py +0 -0
  112. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/locustfile.py +0 -0
  113. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/manual_stats_reporting.py +0 -0
  114. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/multiple_hosts.py +0 -0
  115. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/nested_inline_tasksets.py +0 -0
  116. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/rest.py +0 -0
  117. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/sdk_session_patching/session_patch_locustfile.py +0 -0
  118. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/semaphore_wait.py +0 -0
  119. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/stop_on_threshold.py +0 -0
  120. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/README.md +0 -0
  121. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/data_subnet.tf +0 -0
  122. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/main.tf +0 -0
  123. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/output.tf +0 -0
  124. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/plan/basic.py +0 -0
  125. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/provisioner.tf +0 -0
  126. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/terraform/aws/variables.tf +0 -0
  127. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/test_data_management.py +0 -0
  128. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/use_as_lib.py +0 -0
  129. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/vagrant/README.md +0 -0
  130. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/vagrant/supervisord.conf +0 -0
  131. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/web_ui_auth.py +0 -0
  132. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/examples/worker_index.py +0 -0
  133. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/generate_changelog.py +0 -0
  134. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/__init__.py +0 -0
  135. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/__main__.py +0 -0
  136. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/clients.py +0 -0
  137. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/contrib/__init__.py +0 -0
  138. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/contrib/fasthttp.py +0 -0
  139. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/debug.py +0 -0
  140. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/dispatch.py +0 -0
  141. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/env.py +0 -0
  142. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/event.py +0 -0
  143. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/exception.py +0 -0
  144. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/html.py +0 -0
  145. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/input_events.py +0 -0
  146. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/log.py +0 -0
  147. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/main.py +0 -0
  148. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/py.typed +0 -0
  149. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/rpc/__init__.py +0 -0
  150. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/rpc/protocol.py +0 -0
  151. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/rpc/zmqrpc.py +0 -0
  152. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/shape.py +0 -0
  153. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/chart.js +0 -0
  154. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/css/application.css +0 -0
  155. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/css/application.css.map +0 -0
  156. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/css/tables.css +0 -0
  157. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/css/tables.css.map +0 -0
  158. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/echarts.common.min.js +0 -0
  159. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/favicon.ico +0 -0
  160. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/logo.png +0 -0
  161. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/ui-screenshot-charts.png +0 -0
  162. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/ui-screenshot-start-test.png +0 -0
  163. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/ui-screenshot-stats.png +0 -0
  164. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/img/ui-screenshot-workers.png +0 -0
  165. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/jquery-1.11.3.min.js +0 -0
  166. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/jquery.jqote2.min.js +0 -0
  167. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/jquery.tools.min.js +0 -0
  168. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/locust.js +0 -0
  169. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/sass/_base.sass +0 -0
  170. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/sass/_mixins.sass +0 -0
  171. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/sass/application.sass +0 -0
  172. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/sass/tables.sass +0 -0
  173. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/tasks.js +0 -0
  174. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/static/vintage.js +0 -0
  175. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/stats.py +0 -0
  176. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/templates/index.html +0 -0
  177. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/templates/report.html +0 -0
  178. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/templates/stats_data.html +0 -0
  179. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/__init__.py +0 -0
  180. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/fake_module1_for_env_test.py +0 -0
  181. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/fake_module2_for_env_test.py +0 -0
  182. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/mock_locustfile.py +0 -0
  183. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/mock_logging.py +0 -0
  184. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_debugging.py +0 -0
  185. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_dispatch.py +0 -0
  186. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_env.py +0 -0
  187. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_fasthttp.py +0 -0
  188. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_http.py +0 -0
  189. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_interruptable_task.py +0 -0
  190. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_load_locustfile.py +0 -0
  191. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_locust_class.py +0 -0
  192. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_log.py +0 -0
  193. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_old_wait_api.py +0 -0
  194. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_parser.py +0 -0
  195. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_runners.py +0 -0
  196. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_sequential_taskset.py +0 -0
  197. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_stats.py +0 -0
  198. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_tags.py +0 -0
  199. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_taskratio.py +0 -0
  200. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_users.py +0 -0
  201. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_util.py +0 -0
  202. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_wait_time.py +0 -0
  203. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_web.py +0 -0
  204. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/test_zmqrpc.py +0 -0
  205. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/testcases.py +0 -0
  206. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/test/util.py +0 -0
  207. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/__init__.py +0 -0
  208. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/inspectuser.py +0 -0
  209. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/sequential_taskset.py +0 -0
  210. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/task.py +0 -0
  211. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/users.py +0 -0
  212. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/user/wait_time.py +0 -0
  213. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/__init__.py +0 -0
  214. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/cache.py +0 -0
  215. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/deprecation.py +0 -0
  216. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/exception_handler.py +0 -0
  217. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/load_locustfile.py +0 -0
  218. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/rounding.py +0 -0
  219. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/util/timespan.py +0 -0
  220. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/web.py +0 -0
  221. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/.eslintrc +0 -0
  222. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/.gitignore +0 -0
  223. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/.prettierrc +0 -0
  224. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/auth.html +0 -0
  225. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dev.html +0 -0
  226. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dist/assets/favicon.ico +0 -0
  227. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dist/assets/logo.png +0 -0
  228. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/dist/report.html +0 -0
  229. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/index.html +0 -0
  230. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/package.json +0 -0
  231. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/public/assets/favicon.ico +0 -0
  232. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/public/assets/logo.png +0 -0
  233. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/public/report.html +0 -0
  234. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/App.tsx +0 -0
  235. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/Report.tsx +0 -0
  236. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/auth.tsx +0 -0
  237. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/DataTable/DataTable.test.tsx +0 -0
  238. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/DataTable/DataTable.tsx +0 -0
  239. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/ExceptionsTable/ExceptionsTable.tsx +0 -0
  240. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Form/Form.tsx +0 -0
  241. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Form/Select.tsx +0 -0
  242. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Form/tests/Form.test.tsx +0 -0
  243. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Form/tests/Select.test.tsx +0 -0
  244. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Footer/About.tsx +0 -0
  245. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Footer/Footer.tsx +0 -0
  246. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Layout.tsx +0 -0
  247. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Navbar/DarkLightToggle.tsx +0 -0
  248. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Navbar/Navbar.tsx +0 -0
  249. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Navbar/SwarmMonitor.test.tsx +0 -0
  250. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Layout/Navbar/SwarmMonitor.tsx +0 -0
  251. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LineChart/LineChart.test.tsx +0 -0
  252. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LineChart/LineChart.tsx +0 -0
  253. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LogViewer/LogViewer.tsx +0 -0
  254. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LogViewer/tests/LogViewer.test.tsx +0 -0
  255. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LogViewer/tests/useLogViewer.test.tsx +0 -0
  256. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/LogViewer/useLogViewer.ts +0 -0
  257. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Modal/Modal.tsx +0 -0
  258. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Reports/Reports.test.tsx +0 -0
  259. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Reports/Reports.tsx +0 -0
  260. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.test.tsx +0 -0
  261. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/EditButton.tsx +0 -0
  262. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/NewTestButton.tsx +0 -0
  263. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/ResetButton.tsx +0 -0
  264. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/StateButtons.tsx +0 -0
  265. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/StopButton.tsx +0 -0
  266. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/tests/ResetButton.test.tsx +0 -0
  267. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/tests/StateButtons.test.tsx +0 -0
  268. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/StateButtons/tests/StopButton.test.tsx +0 -0
  269. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmCharts/SwarmCharts.tsx +0 -0
  270. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/SwarmCustomParameters.tsx +0 -0
  271. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/SwarmEditForm.tsx +0 -0
  272. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/SwarmForm.tsx +0 -0
  273. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/SwarmUserClassPicker.tsx +0 -0
  274. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/tests/SwarmCustomParameters.test.tsx +0 -0
  275. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/tests/SwarmEditForm.test.tsx +0 -0
  276. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/tests/SwarmForm.test.tsx +0 -0
  277. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmForm/tests/SwarmUserClassPicker.test.tsx +0 -0
  278. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmRatios/SwarmRatios.test.tsx +0 -0
  279. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/SwarmRatios/SwarmRatios.tsx +0 -0
  280. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Tabs/Tabs.constants.tsx +0 -0
  281. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Tabs/Tabs.test.tsx +0 -0
  282. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/Tabs/Tabs.tsx +0 -0
  283. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.test.tsx +0 -0
  284. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.tsx +0 -0
  285. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/constants/swarm.tsx +0 -0
  286. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/constants/theme.ts +0 -0
  287. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/global.d.ts +0 -0
  288. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/tests/useNotifications.test.tsx +0 -0
  289. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/tests/useSelecteViewColumns.test.tsx +0 -0
  290. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/tests/useSwarmUi.test.tsx +0 -0
  291. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/useInterval.ts +0 -0
  292. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/useNotifications.ts +0 -0
  293. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/useSelectViewColumns.ts +0 -0
  294. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/hooks/useSwarmUi.ts +0 -0
  295. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/index.tsx +0 -0
  296. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/api/swarm.ts +0 -0
  297. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/hooks.ts +0 -0
  298. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/logViewer.slice.ts +0 -0
  299. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/notification.slice.ts +0 -0
  300. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/root.slice.ts +0 -0
  301. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/swarm.slice.ts +0 -0
  302. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/tests/ui.slice.test.ts +0 -0
  303. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/theme.slice.ts +0 -0
  304. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/ui.slice.ts +0 -0
  305. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/slice/url.slice.ts +0 -0
  306. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/store.ts +0 -0
  307. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/redux/utils.ts +0 -0
  308. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/styles/theme.ts +0 -0
  309. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/test/constants.ts +0 -0
  310. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/test/mocks/statsRequest.mock.ts +0 -0
  311. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/test/mocks/swarmState.mock.ts +0 -0
  312. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/test/setup.ts +0 -0
  313. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/test/testUtils.tsx +0 -0
  314. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/types/auth.types.ts +0 -0
  315. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/types/swarm.types.ts +0 -0
  316. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/types/tab.types.ts +0 -0
  317. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/types/table.types.ts +0 -0
  318. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/types/ui.types.ts +0 -0
  319. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/number.ts +0 -0
  320. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/object.ts +0 -0
  321. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/string.ts +0 -0
  322. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/tests/number.test.ts +0 -0
  323. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/tests/object.test.ts +0 -0
  324. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/tests/string.test.ts +0 -0
  325. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/tests/url.test.ts +0 -0
  326. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/src/utils/url.ts +0 -0
  327. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/tsconfig.json +0 -0
  328. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/vitest.config.ts +0 -0
  329. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust/webui/yarn.lock +0 -0
  330. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/dependency_links.txt +0 -0
  331. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/entry_points.txt +0 -0
  332. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/not-zip-safe +0 -0
  333. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/requires.txt +0 -0
  334. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/locust.egg-info/top_level.txt +0 -0
  335. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/package.json +0 -0
  336. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/pyproject.toml +0 -0
  337. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/scripts/locustfile.py +0 -0
  338. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/scripts/run-disributed-headless.sh +0 -0
  339. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/scripts/run-disributed-web.sh +0 -0
  340. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/scripts/run-local-headless.sh +0 -0
  341. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/scripts/run-local-web.sh +0 -0
  342. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/setup.cfg +0 -0
  343. {locust-2.22.1.dev45 → locust-2.22.1.dev67}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: locust
3
- Version: 2.22.1.dev45
3
+ Version: 2.22.1.dev67
4
4
  Summary: Developer friendly load testing framework
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://locust.io/
@@ -38,16 +38,19 @@ Start locust in master mode on one machine::
38
38
 
39
39
  locust -f my_locustfile.py --master
40
40
 
41
- And then on each worker machine (make sure they also have a copy of the locustfile):
41
+ And then on each worker machine:
42
42
 
43
43
  .. code-block:: bash
44
44
 
45
- locust -f my_locustfile.py --worker --master-host <your master's address> --processes 4
45
+ locust -f - --worker --master-host <your master's address> --processes 4
46
+
47
+ .. note::
48
+ The ``-f -`` argument tells Locust to get the locustfile from master instead of from its local filesystem. This feature was introduced in Locust 2.23.0.
46
49
 
47
50
  Multiple machines, using locust-swarm
48
51
  =====================================
49
52
 
50
- Both worker and master need access to the locustfile, and when you make changes to it you'll need to restart all Locust processes. `locust-swarm <https://github.com/SvenskaSpel/locust-swarm>`_ automates this for you. It also solves the issue of firewall/network access from workers to master using SSH tunnels (this is often a problem if the master is running on your workstation and workers are running in some datacenter).
53
+ When you make changes to the locustfile you'll need to restart all Locust processes. `locust-swarm <https://github.com/SvenskaSpel/locust-swarm>`_ automates this for you. It also solves the issue of firewall/network access from workers to master using SSH tunnels (this is often a problem if the master is running on your workstation and workers are running in some datacenter).
51
54
 
52
55
  .. code-block:: bash
53
56
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.22.1.dev45'
16
- __version_tuple__ = version_tuple = (2, 22, 1, 'dev45')
15
+ __version__ = version = '2.22.1.dev67'
16
+ __version_tuple__ = version_tuple = (2, 22, 1, 'dev67')
@@ -1,14 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import locust
4
+ from locust import runners
5
+ from locust.rpc import Message, zmqrpc
4
6
 
5
7
  import os
6
8
  import platform
9
+ import socket
7
10
  import sys
8
11
  import textwrap
9
12
  from typing import Any, NamedTuple
13
+ from uuid import uuid4
10
14
 
11
15
  import configargparse
16
+ import gevent
17
+ from gevent.event import Event
12
18
 
13
19
  version = locust.__version__
14
20
 
@@ -175,6 +181,46 @@ See documentation for more details, including how to set options using a file or
175
181
  return parser
176
182
 
177
183
 
184
+ def download_locustfile_from_master(master_host: str, master_port: int) -> str:
185
+ client_id = socket.gethostname() + "_download_locustfile_" + uuid4().hex
186
+ tempclient = zmqrpc.Client(master_host, master_port, client_id)
187
+ got_reply = False
188
+
189
+ def ask_for_locustfile():
190
+ while not got_reply:
191
+ tempclient.send(Message("locustfile", None, client_id))
192
+ gevent.sleep(1)
193
+
194
+ def wait_for_reply():
195
+ return tempclient.recv()
196
+
197
+ gevent.spawn(ask_for_locustfile)
198
+ try:
199
+ # wait same time as for client_ready ack. not that it is really relevant...
200
+ msg = gevent.spawn(wait_for_reply).get(timeout=runners.CONNECT_TIMEOUT * runners.CONNECT_RETRY_COUNT)
201
+ got_reply = True
202
+ except gevent.Timeout:
203
+ sys.stderr.write(
204
+ f"Got no locustfile response from master, gave up after {runners.CONNECT_TIMEOUT * runners.CONNECT_RETRY_COUNT}s\n"
205
+ )
206
+ sys.exit(1)
207
+
208
+ if msg.type != "locustfile":
209
+ sys.stderr.write(f"Got wrong message type from master {msg.type}\n")
210
+ sys.exit(1)
211
+
212
+ if "error" in msg.data:
213
+ sys.stderr.write(f"Got error from master: {msg.data['error']}\n")
214
+ sys.exit(1)
215
+
216
+ filename = msg.data["filename"]
217
+ with open(filename, "w") as local_file:
218
+ local_file.write(msg.data["contents"])
219
+
220
+ tempclient.close()
221
+ return filename
222
+
223
+
178
224
  def parse_locustfile_option(args=None) -> list[str]:
179
225
  """
180
226
  Construct a command line parser that is only used to parse the -f argument so that we can
@@ -197,9 +243,41 @@ def parse_locustfile_option(args=None) -> list[str]:
197
243
  action="store_true",
198
244
  default=False,
199
245
  )
246
+ # the following arguments are only used for downloading the locustfile from master
247
+ parser.add_argument(
248
+ "--worker",
249
+ action="store_true",
250
+ env_var="LOCUST_MODE_WORKER",
251
+ )
252
+ parser.add_argument(
253
+ "--master", # this is just here to prevent argparse from giving the dreaded "ambiguous option: --master could match --master-host, --master-port"
254
+ action="store_true",
255
+ env_var="LOCUST_MODE_MASTER",
256
+ )
257
+ parser.add_argument(
258
+ "--master-host",
259
+ default="127.0.0.1",
260
+ env_var="LOCUST_MASTER_NODE_HOST",
261
+ )
262
+ parser.add_argument(
263
+ "--master-port",
264
+ type=int,
265
+ default=5557,
266
+ env_var="LOCUST_MASTER_NODE_PORT",
267
+ )
200
268
 
201
269
  options, _ = parser.parse_known_args(args=args)
202
270
 
271
+ if options.locustfile == "-":
272
+ if not options.worker:
273
+ sys.stderr.write(
274
+ "locustfile was set to '-' (meaning to download from master) but --worker was not specified.\n"
275
+ )
276
+ sys.exit(1)
277
+ # having this in argument_parser module is a bit weird, but it needs to be done early
278
+ filename = download_locustfile_from_master(options.master_host, options.master_port)
279
+ return [filename]
280
+
203
281
  # Comma separated string to list
204
282
  locustfile_as_list = [locustfile.strip() for locustfile in options.locustfile.split(",")]
205
283
 
@@ -457,7 +535,7 @@ Typically ONLY these options (and --locustfile) need to be specified on workers,
457
535
  worker_group.add_argument(
458
536
  "--worker",
459
537
  action="store_true",
460
- help="Set locust to run in distributed mode with this process as worker",
538
+ help="Set locust to run in distributed mode with this process as worker. Can be combined with setting --locustfile to '-' to download it from master.",
461
539
  env_var="LOCUST_MODE_WORKER",
462
540
  )
463
541
  worker_group.add_argument(
@@ -1033,6 +1033,40 @@ class MasterRunner(DistributedRunner):
1033
1033
  # emit a warning if the worker's clock seem to be out of sync with our clock
1034
1034
  # if abs(time() - msg.data["time"]) > 5.0:
1035
1035
  # warnings.warn("The worker node's clock seem to be out of sync. For the statistics to be correct the different locust servers need to have synchronized clocks.")
1036
+ elif msg.type == "locustfile":
1037
+ logging.debug("Worker requested locust file")
1038
+ assert self.environment.parsed_options
1039
+ filename = (
1040
+ "locustfile.py"
1041
+ if self.environment.parsed_options.locustfile == "locustfile"
1042
+ else self.environment.parsed_options.locustfile
1043
+ )
1044
+ try:
1045
+ with open(filename) as f:
1046
+ file_contents = f.read()
1047
+ except Exception as e:
1048
+ logger.error(
1049
+ f"--locustfile must be a plain filename (not a module name) for file distribution to work {e}"
1050
+ )
1051
+ self.send_message(
1052
+ "locustfile",
1053
+ client_id=client_id,
1054
+ data={
1055
+ "error": f"locustfile parameter on master must be a plain filename (not a module name) (was '{filename}')"
1056
+ },
1057
+ )
1058
+ else:
1059
+ if getattr(self, "_old_file_contents", file_contents) != file_contents:
1060
+ logger.warning(
1061
+ "Locustfile contents changed on disk after first worker requested locustfile, sending new content. If you make any major changes (like changing User class names) you need to restart master."
1062
+ )
1063
+ self._old_file_contents = file_contents
1064
+ self.send_message(
1065
+ "locustfile",
1066
+ client_id=client_id,
1067
+ data={"filename": filename, "contents": file_contents},
1068
+ )
1069
+ continue
1036
1070
  elif msg.type == "client_stopped":
1037
1071
  if msg.node_id not in self.clients:
1038
1072
  logger.warning(f"Received {msg.type} message from an unknown worker: {msg.node_id}.")
@@ -21,6 +21,8 @@ from pyquery import PyQuery as pq
21
21
  from .mock_locustfile import MOCK_LOCUSTFILE_CONTENT, mock_locustfile
22
22
  from .util import get_free_tcp_port, patch_env, temporary_file
23
23
 
24
+ SHORT_SLEEP = 2 if sys.platform == "darwin" else 1 # macOS is slow on GH, give it some extra time
25
+
24
26
 
25
27
  def is_port_in_use(port: int) -> bool:
26
28
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
@@ -202,7 +204,7 @@ class StandaloneIntegrationTests(ProcessIntegrationTest):
202
204
  )
203
205
  ) as file_path:
204
206
  proc = subprocess.Popen(["locust", "-f", file_path], stdout=PIPE, stderr=PIPE, text=True)
205
- gevent.sleep(1)
207
+ gevent.sleep(SHORT_SLEEP)
206
208
  proc.send_signal(signal.SIGTERM)
207
209
  stdout, stderr = proc.communicate()
208
210
  self.assertIn("Starting web interface at", stderr)
@@ -295,7 +297,7 @@ class StandaloneIntegrationTests(ProcessIntegrationTest):
295
297
  proc = subprocess.Popen(
296
298
  ["locust", "-f", f"{mocked1.file_path},{mocked2.file_path}"], stdout=PIPE, stderr=PIPE, text=True
297
299
  )
298
- gevent.sleep(1)
300
+ gevent.sleep(SHORT_SLEEP)
299
301
  proc.send_signal(signal.SIGTERM)
300
302
  stdout, stderr = proc.communicate()
301
303
  self.assertIn("Starting web interface at", stderr)
@@ -310,7 +312,7 @@ class StandaloneIntegrationTests(ProcessIntegrationTest):
310
312
  with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_A, dir=temp_dir):
311
313
  with mock_locustfile(content=MOCK_LOCUSTFILE_CONTENT_B, dir=temp_dir):
312
314
  proc = subprocess.Popen(["locust", "-f", temp_dir], stdout=PIPE, stderr=PIPE, text=True)
313
- gevent.sleep(1)
315
+ gevent.sleep(SHORT_SLEEP)
314
316
  proc.send_signal(signal.SIGTERM)
315
317
  stdout, stderr = proc.communicate()
316
318
  self.assertIn("Starting web interface at", stderr)
@@ -355,7 +357,7 @@ class StandaloneIntegrationTests(ProcessIntegrationTest):
355
357
  proc = subprocess.Popen(
356
358
  ["locust", "-f", f"{mocked1.file_path},{mocked2}"], stdout=PIPE, stderr=PIPE, text=True
357
359
  )
358
- gevent.sleep(1)
360
+ gevent.sleep(SHORT_SLEEP)
359
361
  proc.send_signal(signal.SIGTERM)
360
362
  stdout, stderr = proc.communicate()
361
363
  self.assertIn("Starting web interface at", stderr)
@@ -1660,6 +1662,171 @@ class SecondUser(HttpUser):
1660
1662
  self.assertEqual(0, proc.returncode)
1661
1663
  self.assertEqual(0, proc_worker.returncode)
1662
1664
 
1665
+ def test_locustfile_distribution(self):
1666
+ LOCUSTFILE_CONTENT = textwrap.dedent(
1667
+ """
1668
+ from locust import User, task, constant
1669
+
1670
+ class User1(User):
1671
+ wait_time = constant(1)
1672
+
1673
+ @task
1674
+ def t(self):
1675
+ pass
1676
+ """
1677
+ )
1678
+ with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked:
1679
+ proc = subprocess.Popen(
1680
+ [
1681
+ "locust",
1682
+ "-f",
1683
+ mocked.file_path,
1684
+ "--headless",
1685
+ "--master",
1686
+ "--expect-workers",
1687
+ "2",
1688
+ "-t",
1689
+ "1s",
1690
+ ],
1691
+ stderr=STDOUT,
1692
+ stdout=PIPE,
1693
+ text=True,
1694
+ )
1695
+ proc_worker = subprocess.Popen(
1696
+ [
1697
+ "locust",
1698
+ "-f",
1699
+ "-",
1700
+ "--worker",
1701
+ ],
1702
+ stderr=STDOUT,
1703
+ stdout=PIPE,
1704
+ text=True,
1705
+ )
1706
+ gevent.sleep(2)
1707
+ # modify the locustfile to trigger warning about file change when the second worker connects
1708
+ with open(mocked.file_path, "w") as locustfile:
1709
+ locustfile.write(LOCUSTFILE_CONTENT)
1710
+ locustfile.write("\n# New comment\n")
1711
+ gevent.sleep(2)
1712
+ proc_worker2 = subprocess.Popen(
1713
+ [
1714
+ "locust",
1715
+ "-f",
1716
+ "-",
1717
+ "--worker",
1718
+ ],
1719
+ stderr=STDOUT,
1720
+ stdout=PIPE,
1721
+ text=True,
1722
+ )
1723
+ stdout = proc.communicate()[0]
1724
+ proc_worker2.communicate()
1725
+ proc_worker.communicate()
1726
+
1727
+ self.assertIn('All users spawned: {"User1": 1} (1 total users)', stdout)
1728
+ self.assertIn("Locustfile contents changed on disk after first worker requested locustfile", stdout)
1729
+ self.assertIn("Shutting down (exit code 0)", stdout)
1730
+
1731
+ self.assertEqual(0, proc.returncode)
1732
+ self.assertEqual(0, proc_worker.returncode)
1733
+
1734
+ def test_locustfile_distribution_with_workers_started_first(self):
1735
+ LOCUSTFILE_CONTENT = textwrap.dedent(
1736
+ """
1737
+ from locust import User, task, constant
1738
+
1739
+ class User1(User):
1740
+ wait_time = constant(1)
1741
+
1742
+ @task
1743
+ def t(self):
1744
+ print("hello")
1745
+ """
1746
+ )
1747
+ with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked:
1748
+ proc_worker = subprocess.Popen(
1749
+ [
1750
+ "locust",
1751
+ "-f",
1752
+ "-",
1753
+ "--worker",
1754
+ ],
1755
+ stderr=STDOUT,
1756
+ stdout=PIPE,
1757
+ text=True,
1758
+ )
1759
+ gevent.sleep(2)
1760
+ proc = subprocess.Popen(
1761
+ [
1762
+ "locust",
1763
+ "-f",
1764
+ mocked.file_path,
1765
+ "--headless",
1766
+ "--master",
1767
+ "--expect-workers",
1768
+ "1",
1769
+ "-t",
1770
+ "1",
1771
+ ],
1772
+ stderr=STDOUT,
1773
+ stdout=PIPE,
1774
+ text=True,
1775
+ )
1776
+
1777
+ stdout = proc.communicate()[0]
1778
+ worker_stdout = proc_worker.communicate()[0]
1779
+
1780
+ self.assertIn('All users spawned: {"User1": ', stdout)
1781
+ self.assertIn("Shutting down (exit code 0)", stdout)
1782
+
1783
+ self.assertEqual(0, proc.returncode)
1784
+ self.assertEqual(0, proc_worker.returncode)
1785
+ self.assertIn("hello", worker_stdout)
1786
+
1787
+ def test_distributed_with_locustfile_distribution_not_plain_filename(self):
1788
+ LOCUSTFILE_CONTENT = textwrap.dedent(
1789
+ """
1790
+ from locust import User, task, constant
1791
+
1792
+ class User1(User):
1793
+ wait_time = constant(1)
1794
+
1795
+ @task
1796
+ def t(self):
1797
+ pass
1798
+ """
1799
+ )
1800
+ with mock_locustfile(content=LOCUSTFILE_CONTENT) as mocked:
1801
+ proc = subprocess.Popen(
1802
+ [
1803
+ "locust",
1804
+ "-f",
1805
+ mocked.file_path[:-3], # remove ".py"
1806
+ "--headless",
1807
+ "--master",
1808
+ ],
1809
+ stderr=STDOUT,
1810
+ stdout=PIPE,
1811
+ text=True,
1812
+ )
1813
+ proc_worker = subprocess.Popen(
1814
+ [
1815
+ "locust",
1816
+ "-f",
1817
+ "-",
1818
+ "--worker",
1819
+ ],
1820
+ stderr=STDOUT,
1821
+ stdout=PIPE,
1822
+ text=True,
1823
+ )
1824
+ stdout = proc_worker.communicate()[0]
1825
+ self.assertIn("Got error from master: locustfile parameter on master must be a plain filename", stdout)
1826
+ proc.kill()
1827
+ master_stdout = proc.communicate()[0]
1828
+ self.assertIn("--locustfile must be a plain filename (not a module name) for file distribut", master_stdout)
1829
+
1663
1830
  def test_json_schema(self):
1664
1831
  LOCUSTFILE_CONTENT = textwrap.dedent(
1665
1832
  """
@@ -1972,18 +2139,19 @@ class AnyUser(HttpUser):
1972
2139
  text=True,
1973
2140
  start_new_session=True,
1974
2141
  )
1975
- gevent.sleep(1)
2142
+ gevent.sleep(2)
1976
2143
  master_proc.kill()
1977
2144
  master_proc.wait()
1978
2145
  try:
1979
- _, worker_stderr = worker_parent_proc.communicate(timeout=7)
2146
+ worker_stdout, worker_stderr = worker_parent_proc.communicate(timeout=7)
1980
2147
  except Exception:
1981
2148
  os.killpg(worker_parent_proc.pid, signal.SIGTERM)
1982
- _, worker_stderr = worker_parent_proc.communicate()
1983
- assert False, f"worker never finished: {worker_stderr}"
2149
+ worker_stdout, worker_stderr = worker_parent_proc.communicate()
2150
+ assert False, f"worker never finished: {worker_stdout} / {worker_stderr}"
1984
2151
 
1985
2152
  self.assertNotIn("Traceback", worker_stderr)
1986
2153
  self.assertIn("Didn't get heartbeat from master in over ", worker_stderr)
2154
+ self.assertIn("worker index:", worker_stdout)
1987
2155
 
1988
2156
  @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows")
1989
2157
  def test_processes_error_doesnt_blow_up_completely(self):
@@ -2010,6 +2178,7 @@ class AnyUser(HttpUser):
2010
2178
  self.assertNotIn("Traceback", stderr)
2011
2179
 
2012
2180
  @unittest.skipIf(os.name == "nt", reason="--processes doesnt work on windows")
2181
+ @unittest.skipIf(sys.platform == "darwin", reason="Flaky on macOS :-/")
2013
2182
  def test_processes_workers_quit_unexpected(self):
2014
2183
  content = """
2015
2184
  from locust import runners, events, User, task