diff --git a/docs/running-in-debugger.rst b/docs/running-in-debugger.rst index bc2842ef57..e3e6e09de2 100644 --- a/docs/running-in-debugger.rst +++ b/docs/running-in-debugger.rst @@ -32,4 +32,6 @@ There is a similar setting in `PyCharm `_ diff --git a/examples/debugging_advanced.py b/examples/debugging_advanced.py new file mode 100644 index 0000000000..ced59da819 --- /dev/null +++ b/examples/debugging_advanced.py @@ -0,0 +1,30 @@ +from locust import HttpUser, task, run_single_user +from locust.exception import StopUser + + +class User1(HttpUser): + host = "http://localhost" + + @task + def hello_world(self): + with self.client.get("/hello1", catch_response=True) as resp: + pass + raise StopUser() + + +class User2(HttpUser): + host = "http://localhost" + + @task + def hello_world(self): + with self.client.get("/hello2", catch_response=True) as resp: + pass + raise StopUser() + + +if __name__ == "__main__": + print("running User1") + run_single_user(User1) + print("running User2") + run_single_user(User2) + print("done!") diff --git a/locust/debug.py b/locust/debug.py index a09d4d5e49..07a3a6ec29 100644 --- a/locust/debug.py +++ b/locust/debug.py @@ -4,6 +4,7 @@ import locust from locust import User, argument_parser from typing import Type +from locust.env import Environment from locust.exception import CatchResponseError @@ -71,6 +72,9 @@ def on_request( print() +_env: Environment = None # minimal Environment for debugging + + def run_single_user( user_class: Type[User], include_length=False, @@ -90,23 +94,25 @@ def run_single_user( By default, it does not set up locusts logging system (because it could interfere with the printing of requests), but you can change that by passing a log level (e.g. *loglevel="INFO"*) """ + global _env + if loglevel: locust.log.setup_logging(loglevel) - # create an environment - env = locust.env.Environment(events=locust.events) - - # in case your test goes looking for the file name of your locustfile - env.parsed_options = argument_parser.parse_options() - frame = inspect.stack()[1] - env.parsed_options.locustfile = os.path.basename(frame[0].f_code.co_filename) - - # log requests to stdout - PrintListener(env, include_length=include_length, include_time=include_time, include_context=include_context) + if not _env: + _env = locust.env.Environment(events=locust.events) + # in case your test goes looking for the file name of your locustfile + _env.parsed_options = argument_parser.parse_options() + frame = inspect.stack()[1] + _env.parsed_options.locustfile = os.path.basename(frame[0].f_code.co_filename) + # log requests to stdout + PrintListener(_env, include_length=include_length, include_time=include_time, include_context=include_context) + # fire various events (quit and test_stop will never get called, sorry about that) + _env.events.init.fire(environment=_env, runner=None, web_ui=None) - # fire various events (quit and test_stop will never get called, sorry about that) - env.events.init.fire(environment=env, runner=None, web_ui=None) - env.events.test_start.fire(environment=env) + _env.events.test_start.fire(environment=_env) # game on! - user_class(env).run() + user = user_class(_env) + _env.single_user_instance = user # if you happen to need access to this from the Environment instance + user.run() diff --git a/tox.ini b/tox.ini index d3a28b3508..70ad1c98d3 100644 --- a/tox.ini +++ b/tox.ini @@ -25,5 +25,8 @@ commands = flake8 . --count --show-source --statistics coverage run -m unittest discover [] black --check . - bash -ec 'timeout 2s python3 examples/debugging.py > output.txt || true' - grep -m 1 '/hello' output.txt + bash -ec 'PYTHONUNBUFFERED=1 timeout 2s python3 examples/debugging.py >out.txt 2>err.txt || true' + grep -m 1 '/hello' out.txt + bash -ec '! grep . err.txt' # should be empty + bash -ec 'PYTHONUNBUFFERED=1 python3 examples/debugging_advanced.py | grep done' +