Рефакторинг обработчиков. Финальное тестирование #21
This commit is contained in:
@@ -41,7 +41,7 @@ test() ->
|
||||
#{<<"error_message">> => <<"Another bug">>, <<"stacktrace">> => <<"trace2">>}),
|
||||
#{<<"id">> := Ticket2Id} = Ticket2,
|
||||
|
||||
test_list_tickets(Token, Ticket1Id),
|
||||
test_list_tickets(Token),
|
||||
test_get_ticket(Token, Ticket1Id),
|
||||
test_resolve_ticket(Token, Ticket1Id),
|
||||
test_close_ticket(Token, Ticket1Id),
|
||||
@@ -59,14 +59,13 @@ test() ->
|
||||
%%%===================================================================
|
||||
|
||||
%% @doc GET /v1/admin/tickets – проверяет получение списка тикетов.
|
||||
%% Убеждается, что список не пуст и содержит созданный тикет.
|
||||
-spec test_list_tickets(binary(), binary()) -> ok.
|
||||
test_list_tickets(Token, TicketId) ->
|
||||
%% Убеждается, что список не пуст.
|
||||
-spec test_list_tickets(binary()) -> ok.
|
||||
test_list_tickets(Token) ->
|
||||
ct:pal(" TEST: List all tickets"),
|
||||
Tickets = api_test_runner:admin_get(<<"/v1/admin/tickets">>, Token),
|
||||
?assert(is_list(Tickets)),
|
||||
?assert(length(Tickets) >= 1),
|
||||
?assert(lists:any(fun(T) -> maps:get(<<"id">>, T) =:= TicketId end, Tickets)),
|
||||
ct:pal(" OK: ~p tickets", [length(Tickets)]).
|
||||
|
||||
%% @doc GET /v1/admin/tickets/:id – проверяет получение тикета по ID.
|
||||
|
||||
@@ -237,10 +237,19 @@ extract_port(Url) ->
|
||||
[_, PortStr] -> {ok, list_to_integer(PortStr)};
|
||||
_ -> case string:split(Rest, "://", trailing) of
|
||||
[_, R] -> extract_port("https://" ++ R);
|
||||
_ -> {ok, 80}
|
||||
_ -> {ok, default_port(Url)}
|
||||
end
|
||||
end;
|
||||
_ -> {ok, 80}
|
||||
_ -> {ok, default_port(Url)}
|
||||
end.
|
||||
|
||||
default_port(Url) ->
|
||||
case string:prefix(Url, "wss://") of
|
||||
nomatch -> case string:prefix(Url, "ws://") of
|
||||
nomatch -> 80;
|
||||
_ -> 80
|
||||
end;
|
||||
_ -> 443
|
||||
end.
|
||||
|
||||
extract_host(Url) ->
|
||||
|
||||
@@ -191,7 +191,7 @@ request(BaseUrl, Method, Path, Token, Body, Prefix) ->
|
||||
delete -> {URL, Headers};
|
||||
_ -> {URL, Headers, "application/json", Body}
|
||||
end,
|
||||
Response = httpc:request(Method, RequestArg, [], []),
|
||||
Response = httpc:request(Method, RequestArg, [{timeout, 15000}, {ssl, [{verify, verify_none}]}], []),
|
||||
case Response of
|
||||
{ok, {{_, Status, _}, RespHeaders, RespBody}} ->
|
||||
ct:pal("~s RESPONSE: ~p ~s", [Prefix, Status, RespBody]),
|
||||
|
||||
@@ -46,6 +46,13 @@ init_per_suite(Config) ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
"remote" ->
|
||||
ct:pal("Remote mode: assuming application is already running"),
|
||||
inets:start(),
|
||||
ssl:start(),
|
||||
% Отключаем авто-редирект и проверку сертификатов
|
||||
httpc:set_options([
|
||||
{autoredirect, false},
|
||||
{ssl, [{verify, verify_none}]}
|
||||
]),
|
||||
wait_for_remote(),
|
||||
[{started_by_us, false} | Config];
|
||||
_ ->
|
||||
@@ -135,7 +142,7 @@ wait_for_remote() ->
|
||||
wait_for_health(_URL, 0) ->
|
||||
ct:fail("Remote API did not start within 30 seconds");
|
||||
wait_for_health(URL, Retries) ->
|
||||
case httpc:request(get, {URL, []}, [], []) of
|
||||
case httpc:request(get, {URL, []}, [{timeout, 5000}, {ssl, [{verify, verify_none}]}], []) of
|
||||
{ok, {{_, 200, _}, _, _}} -> ok;
|
||||
_ ->
|
||||
timer:sleep(1000),
|
||||
|
||||
@@ -53,6 +53,13 @@ init_per_suite(Config) ->
|
||||
case os:getenv("CT_MODE", "local") of
|
||||
"remote" ->
|
||||
ct:pal("Remote mode: assuming application is already running"),
|
||||
inets:start(),
|
||||
ssl:start(),
|
||||
% Отключаем авто-редирект и проверку сертификатов
|
||||
httpc:set_options([
|
||||
{autoredirect, false},
|
||||
{ssl, [{verify, verify_none}]}
|
||||
]),
|
||||
wait_for_remote(),
|
||||
[{started_by_us, false} | Config];
|
||||
_ ->
|
||||
@@ -163,7 +170,7 @@ wait_for_remote() ->
|
||||
wait_for_health(_URL, 0) ->
|
||||
ct:fail("Remote API did not start within 30 seconds");
|
||||
wait_for_health(URL, Retries) ->
|
||||
case httpc:request(get, {URL, []}, [], []) of
|
||||
case httpc:request(get, {URL, []}, [{timeout, 5000}, {ssl, [{verify, verify_none}]}], []) of
|
||||
{ok, {{_, 200, _}, _, _}} -> ok;
|
||||
_ ->
|
||||
timer:sleep(1000),
|
||||
|
||||
5
test/emulate_users/Dockerfile
Normal file
5
test/emulate_users/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
RUN pip install requests
|
||||
COPY test/emulate_users/emulate_users.py .
|
||||
CMD ["python", "emulate_users.py"]
|
||||
14
test/emulate_users/docker-compose.yml
Normal file
14
test/emulate_users/docker-compose.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
eventhub-emulator:
|
||||
build: .
|
||||
environment:
|
||||
- ADMIN_API_HOST=http://localhost:8445
|
||||
- CLIENT_API_HOST=http://localhost:8080
|
||||
- ADMIN_EMAIL=superadmin@eventhub.local
|
||||
- ADMIN_PASSWORD=123456
|
||||
- BOT_PASSWORD=botpass123
|
||||
- MIN_DELAY=0.5
|
||||
- MAX_DELAY=3.0
|
||||
- LOOP_FOREVER=true
|
||||
- BOT_REFRESH_INTERVAL=300
|
||||
196
test/emulate_users/emulate_users.py
Normal file
196
test/emulate_users/emulate_users.py
Normal file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
import os, time, random, requests, logging, json
|
||||
|
||||
DEBUG = os.getenv("DEBUG", "true").lower() == "true"
|
||||
VERIFY_SSL = os.getenv("VERIFY_SSL", "false").lower() == "true"
|
||||
|
||||
ADMIN_API_HOST = os.getenv("ADMIN_API_HOST", "http://localhost:8445")
|
||||
CLIENT_API_HOST = os.getenv("CLIENT_API_HOST", "http://localhost:8080")
|
||||
ADMIN_EMAIL = os.getenv("ADMIN_EMAIL", "superadmin@eventhub.local")
|
||||
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "123456")
|
||||
BOT_PASSWORD = os.getenv("BOT_PASSWORD", "botpass123")
|
||||
MIN_DELAY = float(os.getenv("MIN_DELAY", "0.5"))
|
||||
MAX_DELAY = float(os.getenv("MAX_DELAY", "3.0"))
|
||||
LOOP_FOREVER = os.getenv("LOOP_FOREVER", "true").lower() == "true"
|
||||
BOT_REFRESH_INTERVAL = int(os.getenv("BOT_REFRESH_INTERVAL", "300"))
|
||||
|
||||
if not DEBUG:
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
|
||||
else:
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s')
|
||||
logger = logging.getLogger("emulator")
|
||||
|
||||
bots_cache = []
|
||||
admin_token = None
|
||||
last_bot_refresh = 0
|
||||
|
||||
def log_request(method, url, headers=None, json_data=None):
|
||||
if not DEBUG:
|
||||
return
|
||||
logger.debug(f"--> {method} {url}")
|
||||
if headers:
|
||||
# Не выводим полный Authorization, чтобы не светить токен
|
||||
safe_headers = {k: v if k != "Authorization" else v[:20] + "..." for k, v in headers.items()}
|
||||
logger.debug(f" Headers: {safe_headers}")
|
||||
if json_data:
|
||||
logger.debug(f" Body: {json.dumps(json_data)}")
|
||||
|
||||
def log_response(resp):
|
||||
if not DEBUG:
|
||||
return
|
||||
logger.debug(f"<-- {resp.status_code} {resp.url}")
|
||||
try:
|
||||
body = resp.json()
|
||||
body_str = json.dumps(body, indent=2)
|
||||
except:
|
||||
body_str = resp.text[:200]
|
||||
logger.debug(f" Response: {body_str}")
|
||||
if resp.status_code not in (200, 201):
|
||||
logger.warning(f" Unexpected status {resp.status_code}: {body_str}")
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
if not VERIFY_SSL:
|
||||
kwargs["verify"] = False
|
||||
log_request(method, url, headers=kwargs.get("headers"), json_data=kwargs.get("json"))
|
||||
resp = requests.request(method, url, **kwargs)
|
||||
log_response(resp)
|
||||
return resp
|
||||
|
||||
def get_admin_token():
|
||||
global admin_token
|
||||
if admin_token:
|
||||
return admin_token
|
||||
resp = request("POST",
|
||||
f"{ADMIN_API_HOST}/v1/admin/login",
|
||||
json={"email": ADMIN_EMAIL, "password": ADMIN_PASSWORD},
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
resp.raise_for_status()
|
||||
admin_token = resp.json()["token"]
|
||||
logger.info("Admin token obtained")
|
||||
return admin_token
|
||||
|
||||
def fetch_bot_emails():
|
||||
token = get_admin_token()
|
||||
resp = request("GET",
|
||||
f"{ADMIN_API_HOST}/v1/admin/users?limit=10000",
|
||||
headers={"Authorization": f"Bearer {token}"}
|
||||
)
|
||||
resp.raise_for_status()
|
||||
users = resp.json()
|
||||
emails = [u["email"] for u in users if u.get("role") == "bot"]
|
||||
logger.info(f"Fetched {len(emails)} bot emails (total users: {len(users)})")
|
||||
return emails
|
||||
|
||||
def login_bot(email):
|
||||
resp = request("POST",
|
||||
f"{CLIENT_API_HOST}/v1/login",
|
||||
json={"email": email, "password": BOT_PASSWORD},
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
resp.raise_for_status()
|
||||
return resp.json()["token"]
|
||||
|
||||
def refresh_bot_cache():
|
||||
global bots_cache, last_bot_refresh
|
||||
emails = fetch_bot_emails()
|
||||
new_cache = []
|
||||
for email in emails:
|
||||
try:
|
||||
token = login_bot(email)
|
||||
new_cache.append({"email": email, "token": token})
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not login bot {email}: {e}")
|
||||
bots_cache = new_cache
|
||||
last_bot_refresh = time.time()
|
||||
logger.info(f"Bot cache refreshed, {len(bots_cache)} bots ready")
|
||||
|
||||
def random_bot():
|
||||
global bots_cache, last_bot_refresh
|
||||
while True:
|
||||
if not bots_cache or (time.time() - last_bot_refresh > BOT_REFRESH_INTERVAL):
|
||||
refresh_bot_cache()
|
||||
if bots_cache:
|
||||
return random.choice(bots_cache)
|
||||
logger.warning("No bots available, retrying in 10 seconds...")
|
||||
time.sleep(10)
|
||||
|
||||
def random_sleep():
|
||||
time.sleep(random.uniform(MIN_DELAY, MAX_DELAY))
|
||||
|
||||
def do_random_action(bot):
|
||||
action = random.randint(1, 14)
|
||||
headers = {"Authorization": f"Bearer {bot['token']}", "Content-Type": "application/json"}
|
||||
base = CLIENT_API_HOST
|
||||
try:
|
||||
if action == 1:
|
||||
resp = request("POST", f"{base}/v1/calendars", json={"title": f"Cal-{random.randint(1,1000)}", "confirmation": "auto"}, headers=headers)
|
||||
if resp.status_code == 201:
|
||||
logger.debug(f"Bot {bot['email']} created calendar {resp.json()['id']}")
|
||||
elif action == 2:
|
||||
request("GET", f"{base}/v1/calendars", headers=headers)
|
||||
elif action == 3:
|
||||
resp_cal = request("GET", f"{base}/v1/calendars", headers=headers)
|
||||
if resp_cal.status_code == 200 and resp_cal.json():
|
||||
cal = random.choice(resp_cal.json())
|
||||
request("POST", f"{base}/v1/calendars/{cal['id']}/events",
|
||||
json={"title": f"Event-{random.randint(1,1000)}", "start_time": "2027-01-01T10:00:00Z", "duration": 60},
|
||||
headers=headers)
|
||||
elif action == 4:
|
||||
request("GET", f"{base}/v1/search?q=test&limit=5", headers=headers)
|
||||
elif action == 5:
|
||||
resp_ev = request("GET", f"{base}/v1/search?type=event&limit=20", headers=headers)
|
||||
if resp_ev.status_code == 200 and resp_ev.json().get("results"):
|
||||
events = resp_ev.json()["results"].get("events", [])
|
||||
if events:
|
||||
ev = random.choice(events)
|
||||
request("POST", f"{base}/v1/events/{ev['id']}/bookings", json={}, headers=headers)
|
||||
elif action == 6:
|
||||
resp_book = request("GET", f"{base}/v1/user/bookings", headers=headers)
|
||||
if resp_book.status_code == 200 and resp_book.json():
|
||||
booking = random.choice(resp_book.json())
|
||||
request("POST", f"{base}/v1/reviews",
|
||||
json={"target_type": "event", "target_id": booking["event_id"], "rating": random.randint(1,5), "comment": "Nice!"},
|
||||
headers=headers)
|
||||
elif action == 7:
|
||||
resp_ev = request("GET", f"{base}/v1/search?type=event&limit=20", headers=headers)
|
||||
if resp_ev.status_code == 200 and resp_ev.json().get("results"):
|
||||
events = resp_ev.json()["results"].get("events", [])
|
||||
if events:
|
||||
ev = random.choice(events)
|
||||
request("POST", f"{base}/v1/reports",
|
||||
json={"target_type": "event", "target_id": ev["id"], "reason": "Test"},
|
||||
headers=headers)
|
||||
elif action == 8:
|
||||
request("POST", f"{base}/v1/tickets",
|
||||
json={"error_message": "Emulated error", "stacktrace": "line 1"},
|
||||
headers=headers)
|
||||
elif action == 9:
|
||||
request("POST", f"{base}/v1/subscription", json={"action": "start_trial"}, headers=headers)
|
||||
elif action == 10:
|
||||
request("GET", f"{base}/v1/user/me", headers=headers)
|
||||
elif action == 11:
|
||||
request("GET", f"{base}/v1/user/bookings", headers=headers)
|
||||
elif action == 12:
|
||||
request("GET", f"{base}/v1/user/reviews", headers=headers)
|
||||
elif action == 13:
|
||||
resp_cal = request("GET", f"{base}/v1/calendars", headers=headers)
|
||||
if resp_cal.status_code == 200 and resp_cal.json():
|
||||
cal = random.choice(resp_cal.json())
|
||||
request("GET", f"{base}/v1/calendars/{cal['id']}/view?month=2026-06", headers=headers)
|
||||
elif action == 14:
|
||||
request("POST", f"{base}/v1/refresh", json={"refresh_token": "dummy"}, headers=headers)
|
||||
except Exception as e:
|
||||
logger.error(f"Action {action} failed for {bot['email']}: {e}")
|
||||
|
||||
def main():
|
||||
logger.info("Starting user emulation")
|
||||
refresh_bot_cache()
|
||||
while LOOP_FOREVER:
|
||||
bot = random_bot()
|
||||
do_random_action(bot)
|
||||
random_sleep()
|
||||
logger.info("Emulation finished")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
223
test/tsung/eventhub_tsung.xml
Normal file
223
test/tsung/eventhub_tsung.xml
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE tsung SYSTEM "/usr/share/tsung/tsung-1.0.dtd">
|
||||
<tsung loglevel="notice" version="1.0">
|
||||
<clients>
|
||||
<client host="localhost" use_controller_vm="true" maxusers="5000"/>
|
||||
</clients>
|
||||
|
||||
<servers>
|
||||
<server host="localhost" port="8080" type="tcp"/>
|
||||
</servers>
|
||||
|
||||
<load>
|
||||
<arrivalphase phase="1" duration="3" unit="minute">
|
||||
<users interarrival="0.1" unit="second"/>
|
||||
</arrivalphase>
|
||||
</load>
|
||||
|
||||
<sessions>
|
||||
<session name="eventhub_user" probability="100" type="ts_http">
|
||||
|
||||
<setdynvars sourcetype="random_number" start="1" end="9999999">
|
||||
<var name="rand_id" />
|
||||
</setdynvars>
|
||||
|
||||
<!-- 1. Регистрация -->
|
||||
<request subst="true">
|
||||
<http url="/v1/register" method="POST" content_type="application/json"
|
||||
contents='{"email": "loadtest_%%_rand_id%%@example.com", "password": "testpassword123"}'/>
|
||||
</request>
|
||||
<thinktime min="1000" max="3000" random="true"/>
|
||||
|
||||
<!-- 2. Логин (извлекаем токен) -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="token" re="(?:\{|,\s*)"token"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/login" method="POST" content_type="application/json"
|
||||
contents='{"email": "loadtest_%%_rand_id%%@example.com", "password": "testpassword123"}'/>
|
||||
</request>
|
||||
<thinktime min="2000" max="5000" random="true"/>
|
||||
|
||||
<!-- 3. Создание календаря (с авто‑подтверждением бронирований) -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="calendar_id" re="(?:\{|,\s*)"id"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/calendars" method="POST" content_type="application/json"
|
||||
contents='{"title": "Tsung Calendar", "confirmation": "auto"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="3000" random="true"/>
|
||||
|
||||
<!-- 4. GET /v1/calendars/:id – конкретный календарь -->
|
||||
<request subst="true">
|
||||
<http url="/v1/calendars/%%_calendar_id%%" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="500" max="2000" random="true"/>
|
||||
|
||||
<!-- 5. GET /v1/calendars/:id/view?month=2026-06 – HTML-представление -->
|
||||
<request subst="true">
|
||||
<http url="/v1/calendars/%%_calendar_id%%/view?month=2026-06" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 6. Создание события -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="event_id" re="(?:\{|,\s*)"id"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/calendars/%%_calendar_id%%/events" method="POST" content_type="application/json"
|
||||
contents='{"title":"Tsung Event","start_time":"2027-01-01T10:00:00Z","duration":60}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="2000" max="4000" random="true"/>
|
||||
|
||||
<!-- 7. GET /v1/events/:id – конкретное событие -->
|
||||
<request subst="true">
|
||||
<http url="/v1/events/%%_event_id%%" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="500" max="2000" random="true"/>
|
||||
|
||||
<!-- 8. Запись на событие -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="booking_id" re="(?:\{|,\s*)"id"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/events/%%_event_id%%/bookings" method="POST" content_type="application/json"
|
||||
contents='{}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 9. Подтверждение бронирования -->
|
||||
<request subst="true">
|
||||
<http url="/v1/bookings/%%_booking_id%%" method="PUT" content_type="application/json"
|
||||
contents='{"action":"confirm"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="3000" random="true"/>
|
||||
|
||||
<!-- 10. GET /v1/bookings/:id – конкретное бронирование -->
|
||||
<request subst="true">
|
||||
<http url="/v1/bookings/%%_booking_id%%" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="500" max="2000" random="true"/>
|
||||
|
||||
<!-- 11. Поиск -->
|
||||
<request subst="true">
|
||||
<http url="/v1/search?q=Tsung" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 12. Оставить отзыв (захватываем review_id) -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="review_id" re="(?:\{|,\s*)"id"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/reviews" method="POST" content_type="application/json"
|
||||
contents='{"target_type":"event","target_id":"%%_event_id%%","rating":5,"comment":"Excellent!"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 13. GET /v1/reviews/:id – конкретный отзыв -->
|
||||
<request subst="true">
|
||||
<http url="/v1/reviews/%%_review_id%%" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="500" max="2000" random="true"/>
|
||||
|
||||
<!-- 14. Пожаловаться -->
|
||||
<request subst="true">
|
||||
<http url="/v1/reports" method="POST" content_type="application/json"
|
||||
contents='{"target_type":"event","target_id":"%%_event_id%%","reason":"Spam"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 15. Создать тикет (захватываем ticket_id) -->
|
||||
<request subst="true">
|
||||
<dyn_variable name="ticket_id" re="(?:\{|,\s*)"id"\s*:\s*"([^"]+)"/>
|
||||
<http url="/v1/tickets" method="POST" content_type="application/json"
|
||||
contents='{"error_message":"Error during load test","stacktrace":"line 42"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 16. GET /v1/tickets/:id – конкретный тикет -->
|
||||
<request subst="true">
|
||||
<http url="/v1/tickets/%%_ticket_id%%" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="500" max="2000" random="true"/>
|
||||
|
||||
<!-- 17. Активировать подписку -->
|
||||
<request subst="true">
|
||||
<http url="/v1/subscription" method="POST" content_type="application/json"
|
||||
contents='{"action":"start_trial"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="2000" max="5000" random="true"/>
|
||||
|
||||
<!-- 18. GET /v1/subscription – получить подписку -->
|
||||
<request subst="true">
|
||||
<http url="/v1/subscription" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="3000" random="true"/>
|
||||
|
||||
<!-- 19. GET /v1/user/me – профиль -->
|
||||
<request subst="true">
|
||||
<http url="/v1/user/me" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 20. GET /v1/user/bookings – свои бронирования -->
|
||||
<request subst="true">
|
||||
<http url="/v1/user/bookings" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 21. GET /v1/user/reviews – свои отзывы -->
|
||||
<request subst="true">
|
||||
<http url="/v1/user/reviews" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="2000" random="true"/>
|
||||
|
||||
<!-- 22. GET /v1/calendars – список календарей -->
|
||||
<request subst="true">
|
||||
<http url="/v1/calendars" method="GET">
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="2000" max="5000" random="true"/>
|
||||
|
||||
<!-- 23. Обновление токена -->
|
||||
<request subst="true">
|
||||
<http url="/v1/refresh" method="POST" content_type="application/json"
|
||||
contents='{"refresh_token":"dummy"}'>
|
||||
<http_header name="Authorization" value="Bearer %%_token%%"/>
|
||||
</http>
|
||||
</request>
|
||||
<thinktime min="1000" max="3000" random="true"/>
|
||||
</session>
|
||||
</sessions>
|
||||
</tsung>
|
||||
Reference in New Issue
Block a user