Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting run time from the web UI / http api #2202

Merged
merged 24 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0767f2c
Add parameter for run_time to swarm endpoint
ajt89 Sep 15, 2022
f150ded
Add parameter for run_time to swarm endpoint
ajt89 Sep 15, 2022
bcfe81d
Merge branch 'run-time-input-web' of github.com:ajt89/locust into run…
ajt89 Sep 15, 2022
3bc50d8
Reduce unit test time
ajt89 Sep 16, 2022
95e5af3
Add ui field for run_time
ajt89 Sep 16, 2022
3c5a739
Modernize type hints (#2205)
cyberw Sep 16, 2022
0537b58
Add flag to show run_time in web mode
ajt89 Sep 16, 2022
2935206
Undo line removal
ajt89 Sep 16, 2022
5da71bb
Document how to use separate shape files + shorten tick user_classes …
cyberw Sep 18, 2022
ea91f38
Update web.py to no longer stop runners when using --class-picker
mikenester Sep 18, 2022
1e83ec8
_reset_runners_user_dispatcher -> _reset_user_dispatcher
mikenester Sep 18, 2022
3784866
Merge pull request #2207 from mikenester/bug-fix--user-class-count-re…
cyberw Sep 18, 2022
e955f68
Revert flag for ui run_time
ajt89 Sep 19, 2022
9adbdfd
Add advacned options toggle
ajt89 Sep 19, 2022
81c92a6
Empty commit to re-run tests
ajt89 Sep 19, 2022
fbfc4f0
Add parameter for run_time to swarm endpoint
ajt89 Sep 15, 2022
c02814b
Reduce unit test time
ajt89 Sep 16, 2022
9cd0d02
Add ui field for run_time
ajt89 Sep 16, 2022
e424cd0
Add flag to show run_time in web mode
ajt89 Sep 16, 2022
7882c48
Undo line removal
ajt89 Sep 16, 2022
b61cb7a
Revert flag for ui run_time
ajt89 Sep 19, 2022
6f2c4a9
Add advacned options toggle
ajt89 Sep 19, 2022
0fade1e
Merge branch 'run-time-input-web' of github.com:ajt89/locust into run…
ajt89 Sep 19, 2022
af93494
Add stop_runners function
ajt89 Sep 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions locust/test/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,54 @@ def my_task(self):
self.assertEqual(None, response.json()["host"])
self.assertEqual(self.environment.host, None)

def test_swarm_run_time(self):
class MyUser(User):
wait_time = constant(1)

@task(1)
def my_task(self):
pass

self.environment.user_classes = [MyUser]
self.environment.web_ui.parsed_options = parse_options()
response = requests.post(
"http://127.0.0.1:%i/swarm" % self.web_port,
data={"user_count": 5, "spawn_rate": 5, "host": "https://localhost", "run_time": "5s"},
)
self.assertEqual(200, response.status_code)
self.assertEqual("https://localhost", response.json()["host"])
self.assertEqual(self.environment.host, "https://localhost")
self.assertEqual(5, response.json()["run_time"])
# wait for test to run
gevent.sleep(7)
ajt89 marked this conversation as resolved.
Show resolved Hide resolved
response = requests.get("http://127.0.0.1:%i/stats/requests" % self.web_port)
self.assertEqual("stopped", response.json()["state"])

def test_swarm_run_time_invalid_input(self):
class MyUser(User):
wait_time = constant(1)

@task(1)
def my_task(self):
pass

self.environment.user_classes = [MyUser]
self.environment.web_ui.parsed_options = parse_options()
response = requests.post(
"http://127.0.0.1:%i/swarm" % self.web_port,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test!!

data={"user_count": 5, "spawn_rate": 5, "host": "https://localhost", "run_time": "bad"},
)
self.assertEqual(200, response.status_code)
self.assertEqual(False, response.json()["success"])
self.assertEqual(self.environment.host, "https://localhost")
self.assertEqual(
"Valid run_time formats are : 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.", response.json()["message"]
)
# verify test was not started
response = requests.get("http://127.0.0.1:%i/stats/requests" % self.web_port)
self.assertEqual("ready", response.json()["state"])
requests.get("http://127.0.0.1:%i/stats/reset" % self.web_port)

def test_host_value_from_user_class(self):
class MyUser(User):
host = "http://example.com"
Expand Down
12 changes: 12 additions & 0 deletions locust/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from .user.inspectuser import get_ratio
from .util.cache import memoize
from .util.rounding import proper_round
from .util.timespan import parse_timespan
from .html import get_html_report
from flask_cors import CORS

Expand Down Expand Up @@ -187,6 +188,7 @@ def swarm() -> Response:
self._stop_runners()

parsed_options_dict = vars(environment.parsed_options) if environment.parsed_options else {}
run_time = None
for key, value in request.form.items():
if key == "user_count": # if we just renamed this field to "users" we wouldn't need this
user_count = int(value)
Expand All @@ -198,6 +200,13 @@ def swarm() -> Response:
elif key == "user_classes":
# Set environment.parsed_options.user_classes to the selected user_classes
parsed_options_dict[key] = request.form.getlist("user_classes")
elif key == "run_time":
try:
run_time = parse_timespan(value)
except ValueError:
err_msg = "Valid run_time formats are : 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
logger.error(err_msg)
return jsonify({"success": False, "message": err_msg, "host": environment.host})
elif key in parsed_options_dict:
# update the value in environment.parsed_options, but dont change the type.
# This won't work for parameters that are None
Expand All @@ -221,6 +230,9 @@ def swarm() -> Response:
"message": "Swarming started",
"host": environment.host,
}
if run_time:
gevent.spawn_later(run_time, self._stop_runners).link_exception(greenlet_exception_handler)
response_data["run_time"] = run_time

if self.userclass_picker_is_active:
response_data["user_classes"] = sorted(user_classes.keys())
Expand Down