Способ использования locust.io путем предоставления списка пользователей

Мне нужно провести стресс-тест системы, и http://locust.io кажется лучшим способом сделать это. Однако похоже, что он настроен на использование одного и того же пользователя каждый раз. Мне нужно, чтобы каждый респаун входил в систему как другой пользователь. Как мне это настроить? В качестве альтернативы, есть ли еще одна система, которую можно было бы использовать?


person jloosli    schedule 11.04.2014    source источник


Ответы (4)


Автор Locust здесь.

По умолчанию у каждого пользовательского экземпляра HttpLocust есть HTTP-клиент, у которого есть отдельный сеанс.

Locust не имеет функции для предоставления списка учетных данных пользователя или чего-то подобного. Однако ваши сценарии нагрузочного тестирования - это просто код Python, и, к счастью, реализовать это самостоятельно - тривиально.

Вот небольшой пример:

# locustfile.py

from locust import HttpLocust, TaskSet, task

USER_CREDENTIALS = [
    ("user1", "password"),
    ("user2", "password"),
    ("user3", "password"),
]

class UserBehaviour(TaskSet):
    def on_start(self):
        if len(USER_CREDENTIALS) > 0:
            user, passw = USER_CREDENTIALS.pop()
            self.client.post("/login", {"username":user, "password":passw})

    @task
    def some_task(self):
        # user should be logged in here (unless the USER_CREDENTIALS ran out)
        self.client.get("/protected/resource")

class User(HttpLocust):
    task_set = UserBehaviour
    min_wait = 5000
    max_wait = 60000

Приведенный выше код не будет работать при запуске распределенного Locust, поскольку один и тот же код работает на каждом подчиненном узле, и они не имеют общего состояния. Поэтому вам нужно будет ввести какое-то внешнее хранилище данных, которое подчиненные узлы могут использовать для обмена состояниями (например, PostgreSQL, redis, memcached или что-то еще).

person heyman    schedule 12.04.2014
comment
Что делать, если список пуст? Что произойдет, если мы укажем создание 100 пользователей, но в нашем списке пользователей всего 50 имен? Мы создадим 100 пользователей? - person bearrito; 19.09.2014
comment
Продолжая свой предыдущий вопрос. Что, если мы создадим 50 пользователей, но в нашем списке будет 100 имен, возможно ли убить саранчу. Похоже, что self.interrupt () мог бы это сделать, или я мог бы просто выбросить исключение. - person bearrito; 19.09.2014
comment
В приведенном выше примере вы получите сообщение об ошибке, если создадите больше пользователей, чем у вас есть учетные данные. Экземпляры Locust (пользователи) не должны умирать во время тестового запуска. Если вы хотите смоделировать, что один пользователь уходит, а другой приходит, лучше повторно запустить запущенные экземпляры саранчи. - person heyman; 23.09.2014
comment
Я думаю, что лучший способ - отправить информацию о пользователе в заголовках страниц, требующих входа в систему. - person Mesut GUNES; 07.10.2015
comment
То, что предложил @heyman, определенно сработает, но с использованием БД сложнее, чем это стоит. Я думаю, что каждое ведомое устройство может рандомизировать список и работать только с подмножеством списка. Это должно работать относительно хорошо ... могут быть некоторые учетные данные, которые никогда не вызываются, но опять же, мы проводим здесь нагрузочное тестирование, а не проверяем правильность кода :) - person the1plummie; 21.05.2016
comment
Есть ли способ вернуть пользователя в список после того, как рабочий закончил с ним. Значит, этот тест может выполняться непрерывно, но один и тот же пользователь не вошел в систему одновременно в нескольких сеансах? - person raitisd; 12.09.2016
comment
Или есть способ сбросить список, когда все пользователи закончатся? - person raitisd; 12.09.2016
comment
@raitisd проверьте мое решение ниже. Вы можете использовать его постоянно. - person Mesut GUNES; 23.12.2016

В качестве альтернативы вы можете создать модуль users.py для хранения информации о пользователях, которая вам нужна в ваших тестовых случаях, в моем примере он содержит email и cookies. Затем вы можете вызывать их случайным образом в своих задачах. См. ниже:

# locustfile.py
from locust import HttpLocust, TaskSet, task
from user_agent import *
from users import users_info


class UserBehaviour(TaskSet):
    def get_user(self):
        user = random.choice(users_info)
        return user

    @task(10)
    def get_siparislerim(self):
        user = self.get_user()
        user_agent = self.get_user_agent()
        r = self.client.get("/orders", headers = {"Cookie": user[1], 'User-Agent': user_agent})

class User(HttpLocust):
    task_set = UserBehaviour
    min_wait = 5000
    max_wait = 60000

Пользователь и пользовательский агент могут быть вызваны функцией. Таким образом, мы могли бы распространить тест среди множества пользователей и различных пользовательских агентов.

# users.py

users_info = [
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user'], 
['[email protected]', 'cookies_created_by_each_user']] 
person Mesut GUNES    schedule 07.10.2015
comment
Хорошее предложение. Интересно, что вы могли бы предложить, если бы нужно было использовать данные в последовательном порядке. Выскакивает из массива, как в других предложениях? - person David; 24.07.2017
comment
@David, если вам это нужно, это хорошая идея, так как вы сделали это, вставьте его снова. - person Mesut GUNES; 24.07.2017

При реализации этого для распределенной системы я применил несколько иной подход. Я использовал очень простой фляжный сервер, к которому я обратился во время части on_start TaskSet.

from flask import Flask, jsonify
app = Flask(__name__)

count = 0    #Shared Variable

@app.route("/")
def counter():
    global count

    count = count+1
    tenant = count // 5 + 1
    user = count % 5 + 1

    return jsonify({'count':count,'tenant':"load_tenant_{}".format(str(tenant)),'admin':"admin",'user':"load_user_{}".format(str(user))})

if __name__ == "__main__":
    app.run()

Таким образом, теперь у меня есть конечная точка, которую я могу получить на http://localhost:5000/ на любом хосте, на котором я запускаю этот . Мне просто нужно сделать эту конечную точку доступной для ведомых систем, и мне не придется беспокоиться о дублировании пользователей или о каком-либо эффекте циклического перебора, вызванном ограниченным набором user_info.

person user2943791    schedule 22.03.2016
comment
Помимо распределенного режима, было бы неплохо, если бы это можно было сделать встроенным в locust, чтобы избежать необходимости запускать отдельный сервер. locust имеет встроенный веб-сервис, хотя я бы предпочел не выполнять локальный вызов REST для получения данных. Было бы неплохо получить для справки глобальный счетчик штриховки. - person David; 24.07.2017
comment
Кроме того, для общего набора данных и распределенного тестирования, если набор данных достаточно велик, можно также избежать дублирования из одного набора данных и не использовать здесь свое решение, используя начальные смещения. Каждое ведомое устройство может использовать разное (строка / ключ) смещение для извлечения из набора данных, гарантируя, что они не запускаются одинаково. И если набор данных недостаточно велик, по крайней мере, они используют циклический алгоритм с различным перекрытием. - person David; 24.07.2017
comment
Возможно, я ошибаюсь, но я считаю, что этот подход будет работать только с сервером Flask в режиме разработки / отладки (т.е. однопоточном), потому что в противном случае использование глобальной переменной не является потокобезопасным и может привести к проблемам. - person cjauvin; 08.11.2017
comment
@David Идея номера штриховки обсуждается в задаче Выставить событие on_hatch? И / или номер штриховки (например, мы только что заштриховали номер пользователя X) # 634, и я определенно заинтересован, но, похоже, до сих пор никто не работает над этим. - person Yushin Washio; 10.07.2018
comment
@YushinWashio, на самом деле я предлагал событие on_hatch со счетчиком вылупления ;-) Я бы сам изучил реализацию, если когда-нибудь найду время, чтобы покопаться в исходном коде саранчи. - person David; 11.07.2018

Копирование на ответ @heyman здесь. Код примера будет работать, но продолжение запуска / остановки тестов в конечном итоге очистит список USER_CREDENTIALS и начнет выдавать ошибки.

В итоге я добавил следующее:

from locust import events # in addition to the other locust modules needed

def hatch_complete_handler(**kw):
    global USER_CREDENTIALS
    USER_CREDENTIALS = generate_users() # some function here to regenerate your list

events.hatch_complete += hatch_complete_handler

Это обновит ваш список пользователей, когда ваш рой завершит вылупление.

Также имейте в виду, что вам понадобится список, длина которого превышает количество пользователей, которых вы хотите создать.

person Grey Vugrin    schedule 09.06.2017