Загрузка данных
# Функция принимает 5 параметров:
# 1. response: locust.FastResponse (https://docs.locust.io/en/stable/_modules/locust/contrib/fasthttp.html#FastResponse) для HTTP-зарпосов
# и тело ответа для всех асинхронных операций
# 2. Объект операции (то, вы создавали здесь в UI). Формат операции и ее ключи можно посмотреть в итоговом JSON
# 3. Словарь, "переменная": "значение" с локальными переменными потока
# 4. Список созданных листенеров Kafka, WS, gRPC
# 5. Объект класса UserClass
#
# И должна возвращать 4 параметра:
# 1. Успешность операции (None, если успешность должна быть определена стандартными средствами
# В http по коду ответа, в других протоколах всегда успешно))
# 2. id следующей операции (None, если на этом нужно завершить итерацию)
# 3. Словарь, "переменная": "значение" (может быть пустым - {}) для локальных переменных потока
# 4. Словарь, "переменная": "значение" (может быть пустым - {}) для глобальных переменных теста
from typing import NamedTuple, Optional
import re
# from locust.contrib.fasthttp import ResponseContextManager
# from app.clients.class_builder import UserClass
# from app.data_classes.config import OperationTypes
# from app.data_classes.user_vars import UserVar
# from app.users.async_response_readers import AsyncResponseReader, WebSocketResponseReader, KafkaResponseReader
class ReturnFromPostProcessor(NamedTuple):
is_operation_successful: bool
next_operation_id: Optional[str]
local_vars: dict
global_vars: dict
# def post_processor(response: Union[ResponseContextManager, str, bytes], operation: OperationTypes, user_vars: dict[str, UserVar], listeners: list[AsyncResponseReader], user_class: UserClass, *args, **kwargs) -> ReturnFromPostProcessor:
def post_processor(
response, operation, user_vars, listener, user_class, *args, **kwargs
) -> ReturnFromPostProcessor:
if hasattr(response, "status_code") and response.status_code == 200: # if isinstance(response, ResponseContextManager)
if hasattr(response, "headers") and ('set-cookie' in response.headers) and (len(response.headers["set-cookie"]) > 1):
try:
resp_json = response.json()
if not isinstance(resp_json, dict):
return ReturnFromPostProcessor(False, None, {}, {})
success_data = resp_json.get("success")
if not isinstance(success_data, dict):
return ReturnFromPostProcessor(False, None, {}, {})
sessionId = success_data.get("sbbolSessionId")
if "csrftoken" not in response.headers:
return ReturnFromPostProcessor(False, None, {}, {})
csrftoken = response.headers["csrftoken"]
conf = f"{user_class.environment.config=}"
position = conf.find("UC51_prelogin_mob_AUTH_pp.py")
if position == -1:
return ReturnFromPostProcessor(False, None, {}, {})
pacing = conf[position:position+130]
pacing = pacing.split(",")[3]
position = pacing.find("’")
pacing = pacing[position+1:len(pacing)-1]
position = pacing.find("-")
numA = pacing[0:position]
numB = pacing[position+1:len(pacing)]
iteration = 0
total_iterations = 60
index_header_set_cookies_login = conf.split("UserVar(name=‘index_header_set_cookies_login’, next_value_rule=<NextValueRule.NEVER: ‘never’>, select_rule=None, value=‘")[1][:1]
idx = int(index_header_set_cookies_login)
# Проверяем, что индексов в set-cookie достаточно
if len(response.headers["set-cookie"]) > idx + 1:
TOKEN = response.headers["set-cookie"][idx]
TOKEN_Split = TOKEN.split(';')[0]
SESSION = response.headers["set-cookie"][idx+1]
SESSION_split = SESSION.split(';')[0]
return ReturnFromPostProcessor(True, 'UC51_POST_rest_wholesale_client', {"numA":numA, "numB":numB, "iteration":iteration, "total_iterations":total_iterations, "UFS-TOKEN": TOKEN_Split,"UFS-SESSION":SESSION_split,"csrftoken":csrftoken,"sessionId":sessionId}, {})
except (ValueError, KeyError, IndexError, AttributeError, TypeError):
# Любые ошибки парсинга или несовпадения типов прерывают операцию
pass
return ReturnFromPostProcessor(False, None, {}, {})
elif hasattr(response, "status_code") and response.status_code >= 400:
return ReturnFromPostProcessor(False, None, {}, {})
else:
return ReturnFromPostProcessor(False, None, {}, {})
{
"success": {
"sbbolSessionId": "000000000-0000-0000-0000-000000000000",
"sbbolRouteSessionId": "0||000000000-0000-0000-0000-000000000000"
}
}
200
хэдеры ответа
Server: SynGX
Date: Thu, 25 Jun 2026 10:11:23 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
set-cookie: UFS-TOKEN=db0ca47f-6dbd-45f2-9ffc-fe95987dd030; Path=/; Secure; HttpOnly
set-cookie: UFS-SESSION=lh2C4rq_Tm-T5pQWdqeNmDzYBNg78hI2BRqR_R1FanfS0NsXnjg4TPzxlWDzWbnj; Path=/; Secure; HttpOnly
set-cookie: UFS-SESSION="bd20b86465afb022"; Path=/sds-sticky-session/nonexistent-path; HttpOnly
csrftoken: 7201777588841702108
csrftokensbbid: e08c2fdf-4a8b-4365-bd13-6d118844539a
x-envoy-upstream-service-time: 899
Access-Control-Allow-Credentials: true
Allow: GET, POST, PUT, DELETE, HEAD
Allow: GET, POST, PUT, DELETE, HEAD
X-Frame-Options: SAMEORIGIN
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Encoding: gzip
ufs-business-id: e192a0243cf37adba411850f3236c31b