Skip to content

Commit

Permalink
Merge pull request #2142 from locustio/better-error-message-when-User…
Browse files Browse the repository at this point in the history
….task-is-set-instead-of-User.tasks

Better error message when User.task is set instead of User.tasks
  • Loading branch information
cyberw authored Jul 28, 2022
2 parents 62b486b + a5b31f6 commit c2c9533
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docs/tasksets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ For example, the following code will request URLs /1-/4 in order, and then repea
self.client.get("/1")
self.client.get("/2")
# you can still use the tasks property to specify a list of tasks
# you can still use the tasks attribute to specify a list of tasks
tasks = [function_task]
@task
Expand Down
2 changes: 1 addition & 1 deletion docs/writing-a-locustfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ classes. Say for example, web users are three times more likely than mobile user
...
Also you can set the :py:attr:`fixed_count <locust.User.fixed_count>` attribute.
In this case the weight property will be ignored and the exact count users will be spawned.
In this case the weight attribute will be ignored and the exact count users will be spawned.
These users are spawned first. In the example below, only one instance of AdminUser
will be spawned, to make some specific work with more accurate control
of request count independently of total user count.
Expand Down
4 changes: 2 additions & 2 deletions locust/argument_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,12 +439,12 @@ def setup_parser_arguments(parser):
other_group.add_argument(
"--show-task-ratio",
action="store_true",
help="Print table of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count property.",
help="Print table of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count attribute.",
)
other_group.add_argument(
"--show-task-ratio-json",
action="store_true",
help="Print json data of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count property.",
help="Print json data of the User classes' task execution ratio. Use this with non-zero --user option if some classes define non-zero fixed_count attribute.",
)
# optparse gives you --version but we have to do it ourselves to get -V too
other_group.add_argument(
Expand Down
2 changes: 1 addition & 1 deletion locust/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class HttpSession(requests.Session):
the methods for making requests (get, post, delete, put, head, options, patch, request)
can now take a *url* argument that's only the path part of the URL, in which case the host
part of the URL will be prepended with the HttpSession.base_url which is normally inherited
from a User class' host property.
from a User class' host attribute.
Each of the methods for making requests also takes two additional optional arguments which
are Locust specific and doesn't exist in python-requests. These are:
Expand Down
4 changes: 4 additions & 0 deletions locust/test/test_locust_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ class MyUser(User):
self.assertRaisesRegex(Exception, "No tasks defined on MyTasks.*", l.run)
l.tasks = []
self.assertRaisesRegex(Exception, "No tasks defined on MyTasks.*", l.run)
MyTasks.task = object()
self.assertRaisesRegex(Exception, ".*but you have set a 'task' attribute.*", l.run)

def test_tasks_missing_from_user_gives_user_friendly_exception(self):
class MyUser(User):
wait_time = constant(0.5)

l = MyUser(self.environment)
self.assertRaisesRegex(Exception, "No tasks defined on MyUser.*", l.run)
MyUser.task = object()
self.assertRaisesRegex(Exception, ".*but you have set a 'task' attribute.*", l.run)

def test_task_decorator_ratio(self):
t1 = lambda l: None
Expand Down
2 changes: 1 addition & 1 deletion locust/test/test_runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -2219,7 +2219,7 @@ def my_task(self):
)
)
sleep(0.2)
# hearbeat received from two workers so they are active, for fake_client3 HEARTBEAT_DEAD_INTERNAL has been breached, so it will be removed from worker list
# heartbeat received from two workers so they are active, for fake_client3 HEARTBEAT_DEAD_INTERNAL has been breached, so it will be removed from worker list
self.assertEqual(0, len(master.clients.missing))
self.assertEqual(2, master.worker_count)
master.stop()
Expand Down
2 changes: 1 addition & 1 deletion locust/user/sequential_taskset.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(self, *args, **kwargs):
def get_next_task(self):
if not self.tasks:
raise LocustError(
"No tasks defined. use the @task decorator or set the tasks property of the SequentialTaskSet"
"No tasks defined. Use the @task decorator or set the 'tasks' attribute of the SequentialTaskSet"
)
task = self.tasks[self._task_index % len(self.tasks)]
self._task_index += 1
Expand Down
12 changes: 10 additions & 2 deletions locust/user/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,8 +395,12 @@ def schedule_task(self, task_callable, first=False):

def get_next_task(self):
if not self.tasks:
if getattr(self, "task", None):
extra_message = ", but you have set a 'task' attribute - maybe you meant to set 'tasks'?"
else:
extra_message = "."
raise Exception(
f"No tasks defined on {self.__class__.__name__}. use the @task decorator or set the tasks property of the TaskSet"
f"No tasks defined on {self.__class__.__name__}{extra_message} use the @task decorator or set the 'tasks' attribute of the TaskSet"
)
return random.choice(self.tasks)

Expand Down Expand Up @@ -469,8 +473,12 @@ class DefaultTaskSet(TaskSet):

def get_next_task(self):
if not self.user.tasks:
if getattr(self.user, "task", None):
extra_message = ", but you have set a 'task' attribute on your class - maybe you meant to set 'tasks'?"
else:
extra_message = "."
raise Exception(
f"No tasks defined on {self.user.__class__.__name__}. use the @task decorator or set the tasks property of the User (or mark it as abstract = True if you only intend to subclass it)"
f"No tasks defined on {self.user.__class__.__name__}{extra_message} Use the @task decorator or set the 'tasks' attribute of the User (or mark it as abstract = True if you only intend to subclass it)"
)
return random.choice(self.user.tasks)

Expand Down

0 comments on commit c2c9533

Please sign in to comment.