From 5ece1478f24e4caa37861b8e6c7f75b52840b7b7 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 01:36:57 +0200 Subject: [PATCH 1/8] Group related command line options together using Argument Groups from argparse. Remove deprecated --no-reset-stats options. --- locust/argument_parser.py | 217 +++++++++++++++++++++---------------- locust/test/test_parser.py | 7 -- 2 files changed, 121 insertions(+), 103 deletions(-) diff --git a/locust/argument_parser.py b/locust/argument_parser.py index ec36c3118e..601445a804 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -1,5 +1,7 @@ +import argparse import os import sys +import textwrap import configargparse @@ -59,7 +61,15 @@ def get_empty_argument_parser(add_help=True, default_config_files=DEFAULT_CONFIG default_config_files=default_config_files, auto_env_var_prefix="LOCUST_", add_env_var_help=False, + add_config_file_help=False, add_help=add_help, + formatter_class=argparse.RawDescriptionHelpFormatter, + usage=argparse.SUPPRESS, + description=textwrap.dedent(""" + Usage: locust [OPTIONS] [LocustClass ...] + + """), + #epilog="", ) parser.add_argument( '-f', '--locustfile', @@ -82,7 +92,7 @@ def parse_locustfile_option(args=None): default=False, ) parser.add_argument( - '-V', '--version', + '--version', '-V', action='store_true', default=False, ) @@ -112,205 +122,217 @@ def setup_parser_arguments(parser): Takes a configargparse.ArgumentParser as argument and calls it's add_argument for each of the supported arguments """ + parser._optionals.title = "Common options" parser.add_argument( '-H', '--host', help="Host to load test in the following format: http://10.21.32.33" ) + # Number of Locust users parser.add_argument( + '-c', '--clients', + type=int, + dest='num_clients', + default=1, + help="Number of concurrent Locust users. Only used together with --no-web" + ) + # User hatch rate + parser.add_argument( + '-r', '--hatch-rate', + type=float, + default=1, + help="The rate per second in which clients are spawned. Only used together with --no-web" + ) + # Time limit of the test run + parser.add_argument( + '-t', '--run-time', + help="Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --no-web" + ) + # List locust commands found in loaded locust files/source files + parser.add_argument( + '-l', '--list', + action='store_true', + dest='list_commands', + help="Show list of possible locust classes and exit" + ) + + web_ui_group = parser.add_argument_group("Web UI options") + web_ui_group.add_argument( '--web-host', default="", help="Host to bind the web interface to. Defaults to '' (all interfaces)" ) - parser.add_argument( - '-P', '--web-port', + web_ui_group.add_argument( + '--web-port', '-P', type=int, default=8089, help="Port on which to run web host" ) - # A file that contains the current request stats. - parser.add_argument( - '--csv', '--csv-base-name', - dest='csvfilebase', - help="Store current request stats to files in CSV format.", - ) - # Adds each stats entry at every iteration to the _stats_history.csv file. - parser.add_argument( - '--csv-full-history', + # if we should print stats in the console + web_ui_group.add_argument( + '--no-web', action='store_true', - default=False, - dest='stats_history_enabled', - help="Store each stats entry in CSV format to _stats_history.csv file", + help="Disable the web interface, and instead start running the test immediately. Requires -c and -t to be specified." + ) + + master_worker_group = parser.add_argument_group( + "Master/Worker options", + "Options for running Locust distributed", ) # if locust should be run in distributed mode as master - parser.add_argument( + master_worker_group.add_argument( '--master', action='store_true', help="Set locust to run in distributed mode with this process as master" ) # if locust should be run in distributed mode as worker - parser.add_argument( + master_worker_group.add_argument( '--worker', action='store_true', help="Set locust to run in distributed mode with this process as worker" ) - parser.add_argument( + master_worker_group.add_argument( '--slave', action='store_true', help=configargparse.SUPPRESS ) # master host options - parser.add_argument( + master_worker_group.add_argument( '--master-host', default="127.0.0.1", help="Host or IP address of locust master for distributed load testing. Only used when running with --worker. Defaults to 127.0.0.1." ) - parser.add_argument( + master_worker_group.add_argument( '--master-port', type=int, default=5557, help="The port to connect to that is used by the locust master for distributed load testing. Only used when running with --worker. Defaults to 5557." ) - parser.add_argument( + master_worker_group.add_argument( '--master-bind-host', default="*", help="Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces)." ) - parser.add_argument( + master_worker_group.add_argument( '--master-bind-port', type=int, default=5557, help="Port that locust master should bind to. Only used when running with --master. Defaults to 5557." ) - parser.add_argument( + master_worker_group.add_argument( '--expect-workers', type=int, default=1, help="How many workers master should expect to connect before starting the test (only when --no-web used)." ) - parser.add_argument( + master_worker_group.add_argument( '--expect-slaves', action='store_true', help=configargparse.SUPPRESS ) + + stats_group = parser.add_argument_group("Request statistics") + # A file that contains the current request stats. + stats_group.add_argument( + '--csv', '--csv-base-name', + dest='csvfilebase', + help="Store current request stats to files in CSV format.", + ) + # Adds each stats entry at every iteration to the _stats_history.csv file. + stats_group.add_argument( + '--csv-full-history', + action='store_true', + default=False, + dest='stats_history_enabled', + help="Store each stats entry in CSV format to _stats_history.csv file", + ) # if we should print stats in the console - parser.add_argument( - '--no-web', + stats_group.add_argument( + '--print-stats', action='store_true', - help="Disable the web interface, and instead start running the test immediately. Requires -c and -t to be specified." - ) - # Number of clients - parser.add_argument( - '-c', '--clients', - type=int, - dest='num_clients', - default=1, - help="Number of concurrent Locust users. Only used together with --no-web" + help="Print stats in the console" ) - # Client hatch rate - parser.add_argument( - '-r', '--hatch-rate', - type=float, - default=1, - help="The rate per second in which clients are spawned. Only used together with --no-web" + # only print summary stats + stats_group.add_argument( + '--only-summary', + action='store_true', + help='Only print the summary stats' ) - # Time limit of the test run - parser.add_argument( - '-t', '--run-time', - help="Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --no-web" + stats_group.add_argument( + '--reset-stats', + action='store_true', + help="Reset statistics once hatching has been completed. Should be set on both master and workers when running in distributed mode", ) + + log_group = parser.add_argument_group("Logging options", "Options related to logging") # skip logging setup - parser.add_argument( + log_group.add_argument( '--skip-log-setup', action='store_true', dest='skip_log_setup', default=False, help="Disable Locust's logging setup. Instead, the configuration is provided by the Locust test or Python defaults." ) + # log level + log_group.add_argument( + '--loglevel', '-L', + default='INFO', + help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO.", + ) + # log file + log_group.add_argument( + '--logfile', + help="Path to log file. If not set, log will go to stdout/stderr", + ) + + step_load_group = parser.add_argument_group("Step load options") # Enable Step Load mode - parser.add_argument( + step_load_group.add_argument( '--step-load', action='store_true', help="Enable Step Load mode to monitor how performance metrics varies when user load increases. Requires --step-clients and --step-time to be specified." ) # Number of clients to incease by Step - parser.add_argument( + step_load_group.add_argument( '--step-clients', type=int, default=1, help="Client count to increase by step in Step Load mode. Only used together with --step-load" ) # Time limit of each step - parser.add_argument( + step_load_group.add_argument( '--step-time', help="Step duration in Step Load mode, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --step-load" ) - # log level - parser.add_argument( - '--loglevel', '-L', - default='INFO', - help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO.", - ) - # log file - parser.add_argument( - '--logfile', - help="Path to log file. If not set, log will go to stdout/stderr", - ) - # if we should print stats in the console - parser.add_argument( - '--print-stats', - action='store_true', - help="Print stats in the console" - ) - # only print summary stats - parser.add_argument( - '--only-summary', - action='store_true', - help='Only print the summary stats' - ) - parser.add_argument( - '--no-reset-stats', - action='store_true', - help="[DEPRECATED] Do not reset statistics once hatching has been completed. This is now the default behavior. See --reset-stats to disable", - ) - parser.add_argument( - '--reset-stats', - action='store_true', - help="Reset statistics once hatching has been completed. Should be set on both master and workers when running in distributed mode", - ) - # List locust commands found in loaded locust files/source files - parser.add_argument( - '-l', '--list', - action='store_true', - dest='list_commands', - help="Show list of possible locust classes and exit" - ) + + + other_group = parser.add_argument_group("Other options", "Various other options") # Display ratio table of all tasks - parser.add_argument( + other_group.add_argument( '--show-task-ratio', action='store_true', help="print table of the locust classes' task execution ratio" ) # Display ratio table of all tasks in JSON format - parser.add_argument( + other_group.add_argument( '--show-task-ratio-json', action='store_true', help="print json data of the locust classes' task execution ratio" ) # Version number (optparse gives you --version but we have to do it # ourselves to get -V too. sigh) - parser.add_argument( - '-V', '--version', + other_group.add_argument( + '--version', '-V', action='version', version='%(prog)s {}'.format(version), ) # set the exit code to post on errors - parser.add_argument( + other_group.add_argument( '--exit-code-on-error', type=int, default=1, help="sets the exit code to post on error" ) - parser.add_argument( + other_group.add_argument( '-s', '--stop-timeout', action='store', type=int, @@ -318,10 +340,13 @@ def setup_parser_arguments(parser): default=None, help="Number of seconds to wait for a simulated user to complete any executing task before exiting. Default is to terminate immediately. This parameter only needs to be specified for the master process when running Locust distributed." ) - parser.add_argument( + + locust_classes_group = parser.add_argument_group("Locust user classes") + locust_classes_group.add_argument( 'locust_classes', nargs='*', metavar='LocustClass', + help="Optionally specify which Locust classes that should be used (available Locust classes can be listed with -l or --list)", ) diff --git a/locust/test/test_parser.py b/locust/test/test_parser.py index f55a7a3893..639044aca4 100644 --- a/locust/test/test_parser.py +++ b/locust/test/test_parser.py @@ -26,13 +26,6 @@ def test_reset_stats(self): opts = self.parser.parse_args(args) self.assertEqual(opts.reset_stats, True) - def test_should_accept_legacy_no_reset_stats(self): - args = [ - "--no-reset-stats" - ] - opts = self.parser.parse_args(args) - self.assertEqual(opts.reset_stats, False) - def test_skip_log_setup(self): args = [ "--skip-log-setup" From aafaec35dacafee324701b8e8b3abd7f25dfbf6a Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 01:55:25 +0200 Subject: [PATCH 2/8] Minor formatting and better help message for --exit-code-on-error --- locust/argument_parser.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/locust/argument_parser.py b/locust/argument_parser.py index 601445a804..477ac36e93 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -310,19 +310,20 @@ def setup_parser_arguments(parser): other_group.add_argument( '--show-task-ratio', action='store_true', - help="print table of the locust classes' task execution ratio" + help="Print table of the locust classes' task execution ratio" ) # Display ratio table of all tasks in JSON format other_group.add_argument( '--show-task-ratio-json', action='store_true', - help="print json data of the locust classes' task execution ratio" + help="Print json data of the locust classes' task execution ratio" ) # Version number (optparse gives you --version but we have to do it # ourselves to get -V too. sigh) other_group.add_argument( '--version', '-V', action='version', + help="Show program's version number and exit", version='%(prog)s {}'.format(version), ) # set the exit code to post on errors @@ -330,7 +331,7 @@ def setup_parser_arguments(parser): '--exit-code-on-error', type=int, default=1, - help="sets the exit code to post on error" + help="Sets the process exit code to use when a test result contain any failure or error" ) other_group.add_argument( '-s', '--stop-timeout', From e399cb37230a153d9083723f74b42e583ff3c8ff Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 10:50:10 +0200 Subject: [PATCH 3/8] Remove redundant description and small copy change --- locust/argument_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locust/argument_parser.py b/locust/argument_parser.py index 477ac36e93..320c06ca09 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -230,7 +230,7 @@ def setup_parser_arguments(parser): help=configargparse.SUPPRESS ) - stats_group = parser.add_argument_group("Request statistics") + stats_group = parser.add_argument_group("Request statistics options") # A file that contains the current request stats. stats_group.add_argument( '--csv', '--csv-base-name', @@ -263,7 +263,7 @@ def setup_parser_arguments(parser): help="Reset statistics once hatching has been completed. Should be set on both master and workers when running in distributed mode", ) - log_group = parser.add_argument_group("Logging options", "Options related to logging") + log_group = parser.add_argument_group("Logging options") # skip logging setup log_group.add_argument( '--skip-log-setup', From fdee083048296bab3fd66f5bb6fa88254d0d872c Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 11:04:13 +0200 Subject: [PATCH 4/8] Rename the --no-web option to --headless --- docs/changelog.rst | 1 + docs/retrieving-stats.rst | 4 ++-- docs/running-locust-distributed.rst | 2 +- docs/running-locust-docker.rst | 2 +- docs/running-locust-in-step-load-mode.rst | 2 +- docs/running-locust-without-web-ui.rst | 8 ++++---- locust/argument_parser.py | 12 ++++++------ locust/main.py | 10 +++++----- locust/stats.py | 2 +- 9 files changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f7191b0c05..38d70bfd09 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,7 @@ For full details of the Locust changelog, please see https://github.com/locustio Breaking changes ---------------- +* The option for running Locust without the Web UI has been renamed from ``--no-web`` to ``--headless``. * Removed ``Locust.setup``, ``Locust.teardown``, ``TaskSet.setup`` and ``TaskSet.teardown`` hooks. If you want to run code at the start or end of a test, you should instead use the :py:attr:`test_start ` and :py:attr:`test_stop ` events: diff --git a/docs/retrieving-stats.rst b/docs/retrieving-stats.rst index 8b935625a1..ce3e09ee2a 100644 --- a/docs/retrieving-stats.rst +++ b/docs/retrieving-stats.rst @@ -7,11 +7,11 @@ You may wish to consume your Locust results via a CSV file. In this case, there First, when running Locust with the web UI, you can retrieve CSV files under the Download Data tab. Secondly, you can run Locust with a flag which will periodically save two CSV files. This is particularly useful -if you plan on running Locust in an automated way with the ``--no-web`` flag: +if you plan on running Locust in an automated way with the ``--headless`` flag: .. code-block:: console - $ locust -f examples/basic.py --csv=example --no-web -t10m + $ locust -f examples/basic.py --csv=example --headless -t10m The files will be named ``example_response_times.csv`` and ``example_stats.csv`` (when using ``--csv=example``) and mirror Locust's built in stat pages. diff --git a/docs/running-locust-distributed.rst b/docs/running-locust-distributed.rst index 85b7dc6fd1..7caac89e2a 100644 --- a/docs/running-locust-distributed.rst +++ b/docs/running-locust-distributed.rst @@ -84,7 +84,7 @@ listen to. Defaults to 5557. ``--expect-workers=X`` ---------------------- -Used when starting the master node with ``--no-web``. The master node will then wait until X worker +Used when starting the master node with ``--headless``. The master node will then wait until X worker nodes has connected before the test is started. diff --git a/docs/running-locust-docker.rst b/docs/running-locust-docker.rst index d0f0069ec3..b40ad9b52c 100644 --- a/docs/running-locust-docker.rst +++ b/docs/running-locust-docker.rst @@ -56,7 +56,7 @@ To run in standalone mode without the web UI, you can use the ``LOCUST_OPTS`` en .. code-block:: console - docker run --volume $PWD/dir/of/locustfile:/mnt/locust -e LOCUSTFILE_PATH=/mnt/locust/locustfile.py -e TARGET_URL=https://abc.com -e LOCUST_OPTS="--clients=10 --no-web --run-time=600" locustio/locust + docker run --volume $PWD/dir/of/locustfile:/mnt/locust -e LOCUSTFILE_PATH=/mnt/locust/locustfile.py -e TARGET_URL=https://abc.com -e LOCUST_OPTS="--clients=10 --headless --run-time=600" locustio/locust If you are Kubernetes user, you can use the `Helm chart `_ to scale and run locust. diff --git a/docs/running-locust-in-step-load-mode.rst b/docs/running-locust-in-step-load-mode.rst index beac676543..30510de340 100644 --- a/docs/running-locust-in-step-load-mode.rst +++ b/docs/running-locust-in-step-load-mode.rst @@ -39,7 +39,7 @@ If you want to run Locust in step load mode without the web UI, you can do that .. code-block:: console - $ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --step-load --step-clients 300 --step-time 20m + $ locust -f --headless -c 1000 -r 100 --run-time 1h30m --step-load --step-clients 300 --step-time 20m Locust will swarm the clients by step and shutdown once the time is up. diff --git a/docs/running-locust-without-web-ui.rst b/docs/running-locust-without-web-ui.rst index 8e8ad86278..084c602991 100644 --- a/docs/running-locust-without-web-ui.rst +++ b/docs/running-locust-without-web-ui.rst @@ -5,11 +5,11 @@ Running Locust without the web UI ================================= You can run locust without the web UI - for example if you want to run it in some automated flow, -like a CI server - by using the ``--no-web`` flag together with ``-c`` and ``-r``: +like a CI server - by using the ``--headless`` flag together with ``-c`` and ``-r``: .. code-block:: console - $ locust -f locust_files/my_locust_file.py --no-web -c 1000 -r 100 + $ locust -f locust_files/my_locust_file.py --headless -c 1000 -r 100 ``-c`` specifies the number of Locust users to spawn, and ``-r`` specifies the hatch rate (number of users to spawn per second). @@ -22,7 +22,7 @@ If you want to specify the run time for a test, you can do that with ``--run-tim .. code-block:: console - $ locust -f --no-web -c 1000 -r 100 --run-time 1h30m + $ locust -f --headless -c 1000 -r 100 --run-time 1h30m Locust will shutdown once the time is up. @@ -33,7 +33,7 @@ By default, locust will stop your tasks immediately. If you want to allow your t .. code-block:: console - $ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --stop-timeout 99 + $ locust -f --headless -c 1000 -r 100 --run-time 1h30m --stop-timeout 99 .. _running-locust-distributed-without-web-ui: diff --git a/locust/argument_parser.py b/locust/argument_parser.py index 320c06ca09..543131e3c9 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -133,19 +133,19 @@ def setup_parser_arguments(parser): type=int, dest='num_clients', default=1, - help="Number of concurrent Locust users. Only used together with --no-web" + help="Number of concurrent Locust users. Only used together with --headless" ) # User hatch rate parser.add_argument( '-r', '--hatch-rate', type=float, default=1, - help="The rate per second in which clients are spawned. Only used together with --no-web" + help="The rate per second in which clients are spawned. Only used together with --headless" ) # Time limit of the test run parser.add_argument( '-t', '--run-time', - help="Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --no-web" + help="Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --headless" ) # List locust commands found in loaded locust files/source files parser.add_argument( @@ -169,9 +169,9 @@ def setup_parser_arguments(parser): ) # if we should print stats in the console web_ui_group.add_argument( - '--no-web', + '--headless', action='store_true', - help="Disable the web interface, and instead start running the test immediately. Requires -c and -t to be specified." + help="Disable the web interface, and instead start the load test immediately. Requires -c and -t to be specified." ) master_worker_group = parser.add_argument_group( @@ -222,7 +222,7 @@ def setup_parser_arguments(parser): '--expect-workers', type=int, default=1, - help="How many workers master should expect to connect before starting the test (only when --no-web used)." + help="How many workers master should expect to connect before starting the test (only when --headless used)." ) master_worker_group.add_argument( '--expect-slaves', diff --git a/locust/main.py b/locust/main.py index 837b431272..685cbfa2a2 100644 --- a/locust/main.py +++ b/locust/main.py @@ -206,8 +206,8 @@ def main(): main_greenlet = runner.greenlet if options.run_time: - if not options.no_web: - logger.error("The --run-time argument can only be used together with --no-web") + if not options.headless: + logger.error("The --run-time argument can only be used together with --headless") sys.exit(1) if options.worker: logger.error("--run-time should be specified on the master node, and not on worker nodes") @@ -225,7 +225,7 @@ def timelimit_stop(): gevent.spawn_later(options.run_time, timelimit_stop) # start Web UI - if not options.no_web and not options.worker: + if not options.headless and not options.worker: # spawn web greenlet logger.info("Starting web monitor at http://%s:%s" % (options.web_host or "*", options.web_port)) web_ui = WebUI(environment=environment) @@ -237,7 +237,7 @@ def timelimit_stop(): # need access to the Environment, Runner or WebUI environment.events.init.fire(environment=environment, runner=runner, web_ui=web_ui) - if options.no_web: + if options.headless: # headless mode if options.master: # what for worker nodes to connect @@ -256,7 +256,7 @@ def timelimit_stop(): spawn_run_time_limit_greenlet() stats_printer_greenlet = None - if not options.only_summary and (options.print_stats or (options.no_web and not options.worker)): + if not options.only_summary and (options.print_stats or (options.headless and not options.worker)): # spawn stats printing greenlet stats_printer_greenlet = gevent.spawn(stats_printer(runner.stats)) diff --git a/locust/stats.py b/locust/stats.py index ee7c71e328..f91e9f9b93 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -853,7 +853,7 @@ def stats_history_csv(stats, stats_history_enabled=False, csv_for_web_ui=False): """Returns the Aggregated stats entry every interval""" # csv_for_web_ui boolean returns the header along with the stats history row so that # it can be returned as a csv for download on the web ui. Otherwise when run with - # the '--no-web' option we write the header first and then append the file with stats + # the '--headless' option we write the header first and then append the file with stats # entries every interval. if csv_for_web_ui: rows = [stats_history_csv_header()] From be01965642ad3c7f643b9c53f78ce67fa790fe57 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 11:05:32 +0200 Subject: [PATCH 5/8] Remove redundant description --- locust/argument_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locust/argument_parser.py b/locust/argument_parser.py index 543131e3c9..480f311d5a 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -305,7 +305,7 @@ def setup_parser_arguments(parser): ) - other_group = parser.add_argument_group("Other options", "Various other options") + other_group = parser.add_argument_group("Other options") # Display ratio table of all tasks other_group.add_argument( '--show-task-ratio', From afbc3fd5ef056397c145f00fc0b9a97cb6ba860f Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 12:10:18 +0200 Subject: [PATCH 6/8] Add abstract=True to FastHttpLocust Since we've added the abstract attribute to Locust, locust.main.is_locust no longer need the name of the item it's checking --- locust/contrib/fasthttp.py | 2 ++ locust/main.py | 7 +++---- locust/test/test_fasthttp.py | 5 +++++ locust/test/test_main.py | 14 +++++++------- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/locust/contrib/fasthttp.py b/locust/contrib/fasthttp.py index 0ac735fc17..10828f26b6 100644 --- a/locust/contrib/fasthttp.py +++ b/locust/contrib/fasthttp.py @@ -66,6 +66,8 @@ class by using the :py:func:`@task decorator ` on the methods, The client support cookies, and therefore keeps the session between HTTP requests. """ + abstract = True + # Below are various UserAgent settings. Change these in your subclass to alter FastHttpLocust's behaviour. # It needs to be done before FastHttpLocust is instantiated, changing them later will have no effect diff --git a/locust/main.py b/locust/main.py index 837b431272..b4a3e8ed20 100644 --- a/locust/main.py +++ b/locust/main.py @@ -27,11 +27,10 @@ version = locust.__version__ -def is_locust(tup): +def is_locust(item): """ - Takes (name, object) tuple, returns True if it's a public Locust subclass. + Check if a variable is a runnable (non-abstract) Locust class """ - name, item = tup return bool( inspect.isclass(item) and issubclass(item, Locust) @@ -86,7 +85,7 @@ def __import_locustfile__(filename, path): sys.path.insert(index + 1, directory) del sys.path[0] # Return our two-tuple - locusts = dict(filter(is_locust, vars(imported).items())) + locusts = {name:value for name, value in vars(imported).items() if is_locust(value)} return imported.__doc__, locusts diff --git a/locust/test/test_fasthttp.py b/locust/test/test_fasthttp.py index a4b96820d7..9254fae7f7 100644 --- a/locust/test/test_fasthttp.py +++ b/locust/test/test_fasthttp.py @@ -4,6 +4,7 @@ from locust.core import task, TaskSet from locust.contrib.fasthttp import FastHttpSession, FastHttpLocust from locust.exception import CatchResponseError, InterruptTaskSet, ResponseError +from locust.main import is_locust from .testcases import WebserverTestCase @@ -175,6 +176,10 @@ class MyLocust(FastHttpLocust): class TestFastHttpLocustClass(WebserverTestCase): + def test_is_abstract(self): + self.assertTrue(FastHttpLocust.abstract) + self.assertFalse(is_locust(FastHttpLocust)) + def test_get_request(self): self.response = "" def t1(l): diff --git a/locust/test/test_main.py b/locust/test/test_main.py index afe8bf3110..aa296e9b15 100644 --- a/locust/test/test_main.py +++ b/locust/test/test_main.py @@ -10,10 +10,10 @@ class TestLoadLocustfile(LocustTestCase): def test_is_locust(self): - self.assertFalse(main.is_locust(("Locust", Locust))) - self.assertFalse(main.is_locust(("HttpLocust", HttpLocust))) - self.assertFalse(main.is_locust(("random_dict", {}))) - self.assertFalse(main.is_locust(("random_list", []))) + self.assertFalse(main.is_locust(Locust)) + self.assertFalse(main.is_locust(HttpLocust)) + self.assertFalse(main.is_locust({})) + self.assertFalse(main.is_locust([])) class MyTaskSet(TaskSet): pass @@ -24,13 +24,13 @@ class MyHttpLocust(HttpLocust): class MyLocust(Locust): tasks = [MyTaskSet] - self.assertTrue(main.is_locust(("MyHttpLocust", MyHttpLocust))) - self.assertTrue(main.is_locust(("MyLocust", MyLocust))) + self.assertTrue(main.is_locust(MyHttpLocust)) + self.assertTrue(main.is_locust(MyLocust)) class ThriftLocust(Locust): abstract = True - self.assertFalse(main.is_locust(("ThriftLocust", ThriftLocust))) + self.assertFalse(main.is_locust(ThriftLocust)) def test_load_locust_file_from_absolute_path(self): with mock_locustfile() as mocked: From 25e0bb2fe70a405c90a49133a59165e1ffc22275 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 12:12:55 +0200 Subject: [PATCH 7/8] Oops, @cyberw was faster :) --- locust/contrib/fasthttp.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/locust/contrib/fasthttp.py b/locust/contrib/fasthttp.py index 10828f26b6..a0597dc549 100644 --- a/locust/contrib/fasthttp.py +++ b/locust/contrib/fasthttp.py @@ -66,8 +66,6 @@ class by using the :py:func:`@task decorator ` on the methods, The client support cookies, and therefore keeps the session between HTTP requests. """ - abstract = True - # Below are various UserAgent settings. Change these in your subclass to alter FastHttpLocust's behaviour. # It needs to be done before FastHttpLocust is instantiated, changing them later will have no effect @@ -87,7 +85,7 @@ class by using the :py:func:`@task decorator ` on the methods, """Parameter passed to FastHttpSession. Default True, meaning no SSL verification.""" abstract = True - """dont register this as a locust""" + """Dont register this as a locust that can be run by itself""" def __init__(self, environment): super().__init__(environment) From 02701ad6c1d46314af9ff379f7217891b6920216 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Mon, 6 Apr 2020 12:29:26 +0200 Subject: [PATCH 8/8] Split Master and Worker CLI arguments into two groups --- locust/argument_parser.py | 68 ++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/locust/argument_parser.py b/locust/argument_parser.py index 480f311d5a..231c0c8815 100644 --- a/locust/argument_parser.py +++ b/locust/argument_parser.py @@ -174,61 +174,69 @@ def setup_parser_arguments(parser): help="Disable the web interface, and instead start the load test immediately. Requires -c and -t to be specified." ) - master_worker_group = parser.add_argument_group( - "Master/Worker options", - "Options for running Locust distributed", + master_group = parser.add_argument_group( + "Master options", + "Options for running a Locust Master node when running Locust distributed. A Master node need Worker nodes that connect to it before it can run load tests.", ) # if locust should be run in distributed mode as master - master_worker_group.add_argument( + master_group.add_argument( '--master', action='store_true', help="Set locust to run in distributed mode with this process as master" ) + master_group.add_argument( + '--master-bind-host', + default="*", + help="Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces)." + ) + master_group.add_argument( + '--master-bind-port', + type=int, + default=5557, + help="Port that locust master should bind to. Only used when running with --master. Defaults to 5557." + ) + master_group.add_argument( + '--expect-workers', + type=int, + default=1, + help="How many workers master should expect to connect before starting the test (only when --headless used)." + ) + master_group.add_argument( + '--expect-slaves', + action='store_true', + help=configargparse.SUPPRESS + ) + + worker_group = parser.add_argument_group( + "Worker options", + textwrap.dedent(""" + Options for running a Locust Worker node when running Locust distributed. + Only the LOCUSTFILE (-f option) need to be specified when starting a Worker, since other options such as -c, -r, -t are specified on the Master node. + """), + ) # if locust should be run in distributed mode as worker - master_worker_group.add_argument( + worker_group.add_argument( '--worker', action='store_true', help="Set locust to run in distributed mode with this process as worker" ) - master_worker_group.add_argument( + worker_group.add_argument( '--slave', action='store_true', help=configargparse.SUPPRESS ) # master host options - master_worker_group.add_argument( + worker_group.add_argument( '--master-host', default="127.0.0.1", help="Host or IP address of locust master for distributed load testing. Only used when running with --worker. Defaults to 127.0.0.1." ) - master_worker_group.add_argument( + worker_group.add_argument( '--master-port', type=int, default=5557, help="The port to connect to that is used by the locust master for distributed load testing. Only used when running with --worker. Defaults to 5557." ) - master_worker_group.add_argument( - '--master-bind-host', - default="*", - help="Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces)." - ) - master_worker_group.add_argument( - '--master-bind-port', - type=int, - default=5557, - help="Port that locust master should bind to. Only used when running with --master. Defaults to 5557." - ) - master_worker_group.add_argument( - '--expect-workers', - type=int, - default=1, - help="How many workers master should expect to connect before starting the test (only when --headless used)." - ) - master_worker_group.add_argument( - '--expect-slaves', - action='store_true', - help=configargparse.SUPPRESS - ) stats_group = parser.add_argument_group("Request statistics options") # A file that contains the current request stats.