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

Add parent to TaskSet to enable state sharing among hierarchical TaskSets #50

Merged
merged 1 commit into from
Dec 20, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ dist/**
.idea/**
*.iml
*.ipr
.vagrant
.vagrant
build/
38 changes: 21 additions & 17 deletions locust/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class Locust(object):
"""Number of seconds after which the Locust will die. If None it won't timeout."""

weight = 10
"""Probability of locust beeing choosen. The higher the weight, the greater is the chance of it beeing chosen."""
"""Probability of locust being chosen. The higher the weight, the greater is the chance of it being chosen."""

def __init__(self):
super(Locust, self).__init__()
Expand All @@ -112,7 +112,7 @@ class TaskSetMeta(type):
ratio using an {task:int} dict, or a [(task0,int), ..., (taskN,int)] list.
"""

def __new__(meta, classname, bases, classDict):
def __new__(mcs, classname, bases, classDict):
new_tasks = []
for base in bases:
if hasattr(base, "tasks") and base.tasks:
Expand All @@ -138,20 +138,20 @@ def __new__(meta, classname, bases, classDict):

classDict["tasks"] = new_tasks

return type.__new__(meta, classname, bases, classDict)
return type.__new__(mcs, classname, bases, classDict)

class TaskSet(object):
"""
Class defining a set of tasks that a Locust user will execute.

When a TaskSet starts running, it will pick a task from the *tasks* attribute,
execute it, call it's wait function which will sleep a randomm number between
execute it, call it's wait function which will sleep a random number between
*min_wait* and *max_wait* milliseconds. It will then schedule another task for
execution and so on.

TaskTests can be nested, which means that a TaskSet's *tasks* attribute can contain
another TaskSet. If the nested TaskSet it scheduled to be executed, it will be
instanciated and called from the current executing TaskSet. Execution in the the
instantiated and called from the current executing TaskSet. Execution in the the
currently running TaskSet will then be handed over to the nested TaskSet which will
continue to run until it throws an InterruptTaskSet exception, which is done when
:py:meth:`TaskSet.interrupt() <locust.core.TaskSet.interrupt>` is called. (execution
Expand Down Expand Up @@ -198,7 +198,12 @@ class ForumPage(TaskSet):

locust = None
"""Will refer to the root Locust class when the TaskSet has been instantiated"""


parent = None
"""Will refer to the parent class when the TaskSet has been instantiated
Useful for nested TaskSet classes
"""

__metaclass__ = TaskSetMeta

def __init__(self, parent):
Expand All @@ -213,7 +218,8 @@ def __init__(self, parent):
self.locust = parent
else:
raise LocustError("TaskSet should be called with Locust instance or TaskSet instance as first argument")


self.parent = parent
self.client = self.locust.client

# if this class doesn't have a min_wait, max_wait or avg_wait defined, copy it from Locust
Expand All @@ -232,7 +238,7 @@ def run(self, *args, **kwargs):
self.on_start()
while (True):
try:
if self.locust.stop_timeout is not None and time() - self._time_start > self.stop_timeout:
if self.locust.stop_timeout is not None and time() - self._time_start > self.locust.stop_timeout:
return

if not self._task_queue:
Expand Down Expand Up @@ -276,7 +282,7 @@ def execute_task(self, task, *args, **kwargs):
# task is a function
task(self, *args, **kwargs)

def schedule_task(self, task_callable, args=[], kwargs={}, first=False):
def schedule_task(self, task_callable, args=None, kwargs=None, first=False):
"""
Add a task to the Locust's task execution queue.

Expand All @@ -287,7 +293,7 @@ def schedule_task(self, task_callable, args=[], kwargs={}, first=False):
* kwargs: Dict of keyword arguments that will be passed to the task callable.
* first: Optional keyword argument. If True, the task will be put first in the queue.
"""
task = {"callable":task_callable, "args":args, "kwargs":kwargs}
task = {"callable":task_callable, "args":args or [], "kwargs":kwargs or {}}
if first:
self._task_queue.insert(0, task)
else:
Expand Down Expand Up @@ -339,18 +345,16 @@ def interrupt(self, reschedule=True):
class WebLocust(Locust):
def __init__(self, *args, **kwargs):
warnings.warn("WebLocust class has been, deprecated. Use Locust class instead.")
super(WebLocust, self).__init__(*args, **kwargs)
super(WebLocust, self).__init__()


class SubLocust(object):
def __init__(self, *args, **kwargs):
raise DeprecationWarning("The SubLocust class has been deprecated. Use TaskSet classes instead.")

#class TaskSetNope(TaskSetBase):
"""
Class for making a sub Locust that can be included as a task inside of a normal Locust/WebLocus,
as well as inside another sub locust.
as well as inside another sub locust.

When the parent locust enters the sub locust, it will not
continue executing it's tasks until a task in the sub locust has called the interrupt() function.
"""
def __init__(self, *args, **kwargs):
raise DeprecationWarning("The SubLocust class has been deprecated. Use TaskSet classes instead.")
6 changes: 3 additions & 3 deletions locust/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def fire(self, *args, **kwargs):

* *method*: HTTP Request method used
* *path*: Path to the URL that was called (or override name if it was used in the call to the client)
* *response_time*: Reponse time in milliseconds
* *response_time*: Response time in milliseconds
* *response_length*: Content-length of the response
"""

Expand All @@ -58,7 +58,7 @@ def fire(self, *args, **kwargs):

Event is fired with the following arguments:

* *locust_instance*: Locust class instance where the exception occured
* *locust_instance*: Locust class instance where the exception occurred
* *exception*: Exception that was thrown
* *traceback*: Traceback object (from sys.exc_info()[2])
"""
Expand All @@ -80,7 +80,7 @@ def fire(self, *args, **kwargs):
slave_report = EventHook()
"""
*slave_report* is used when Locust is running in --master mode and is fired when the master
server recieves a report from a Locust slave server.
server receives a report from a Locust slave server.

This event can be used to aggregate data from the locust slave servers.

Expand Down
7 changes: 3 additions & 4 deletions locust/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import os
import signal
import inspect
import time
import logging
from optparse import OptionParser

Expand Down Expand Up @@ -70,7 +69,7 @@ def parse_options():
type='str',
dest='master_host',
default="127.0.0.1",
help="Host or IP adress of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1."
help="Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1."
)

# if we should print stats in the console
Expand Down Expand Up @@ -141,7 +140,7 @@ def parse_options():
help="Enables the auto tuning ramping feature for finding highest stable client count. NOTE having ramp enabled will add some more overhead for additional stats gathering"
)

# if we shgould print stats in the console
# if we should print stats in the console
parser.add_option(
'--print-stats',
action='store_true',
Expand Down Expand Up @@ -295,7 +294,7 @@ def main():
logger = logging.getLogger(__name__)

if options.show_version:
print "Locust %s" % (version)
print "Locust %s" % (version,)
sys.exit(0)

locustfile = find_locustfile(options.locustfile)
Expand Down
2 changes: 1 addition & 1 deletion locust/rpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
try:
import zmqrpc as rpc
except ImportError:
warnings.warn("WARNING: Using pure Python socket RPC implementation instead of zmq. This will not affect you if your not running locust in distributed mode, but if you are, we recommend you to install the python packages: pyzmq and gevent-zeromq")
warnings.warn("WARNING: Using pure Python socket RPC implementation instead of zmq. This will not affect you if you're not running locust in distributed mode, but if you are, we recommend you to install the python packages: pyzmq and gevent-zeromq")
import socketrpc as rpc

Message = namedtuple("Message", ["type", "data", "node_id"])