locustio / locust

Write scalable load tests in plain Python 🚗💨
https://locust.cloud
MIT License
25.02k stars 2.99k forks source link

Sequence does not get past first nested sequence. #1080

Closed stevecj closed 5 years ago

stevecj commented 5 years ago

Description of issue

When the first sequence-task in a task sequence is a class, subsequent sequence-tasks never run.

First, I created a sequence with 3 sequence-task methods, and that worked fine. Next, I moved the first 2 steps into a nested class. Those 2 steps ran, but the remaining step in the outer sequence class did not.

If this is something I'm doing wrong, I can't figure it out, so if this is my misunderstanding, maybe we can have something in the docs to help clarify.

Environment settings

Steps to reproduce (for bug reports)

rom locust import HttpLocust, TaskSequence, task, seq_task

RAD_LOGIN_CREDENTIALS = {"email": "brad@example.com", "password": "password"}

lass UserBehavior(TaskSequence):

   def on_stop(self):
       self.logout()

   @seq_task(1)
   class Login(TaskSequence):
       min_wait = 0
       max_wait = 5

       @seq_task(1)
       def get_info(self):
           self.client.get("/api/v1/info/")

       @seq_task(2)
       def login(self):
           response = self.client.post(
               "/api/v1/private/login/", json=BRAD_LOGIN_CREDENTIALS)
           dh_token = response.json()['dh_token']
           self.client.headers['Authorization'] = f'Token {dh_token}'

   @seq_task(2)
   def view_dashboard(self):
       self.client.get(
           '/api/v1/private/tasks/',
           params={
               'additional_fields':
                   'task_id,object,workflow,actions,type_event',
               'ordering': '-udate',
               'page': '1',
               'page_size': '5',
               'roles': 'requester',
               'ticket_system': 'DesignHUB'})

   def logout(self):
       if self.client.headers.get('Authorization'):
           self.client.post("/api/v1/private/logout/")

class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    min_wait = 4000
    max_wait = 7000

When I run this, I only get output for /api/v1/info/, /api/v1/private/login/, and /api/v1/private/logout/ . When I run this with all 3 sequence task methods in the outer class, numbered 1 through 3, then I also get requests to /api/v1/private/tasks/?… as expected.

stevecj commented 5 years ago

I found the answer myself by reading the source code. I have to call self.interrupt() at the end of the last task in the nested sequence so it doesn't repeat.

Might want to clarify that in the docs.