83 lines
3.7 KiB
Python
83 lines
3.7 KiB
Python
# run.py — CLI запуска нагрузочных сценариев.
|
|
#
|
|
# Примеры:
|
|
# python3 -m loadtests.run baseline --devices 50 --rate 2 --duration 120
|
|
# python3 -m loadtests.run burst --devices 100 --rate 1 --burst-mult 10 --duration 30
|
|
# python3 -m loadtests.run large-payload --payload-size 900000
|
|
# python3 -m loadtests.run reconnect-storm --devices 100 --reconnect-every 30
|
|
# python3 -m loadtests.run multitenant --tenants 20 --devices-per-tenant 3
|
|
# python3 -m loadtests.run acl-violation
|
|
# python3 -m loadtests.run auth-neg
|
|
# python3 -m loadtests.run api-crud --threads 10 --iterations 20
|
|
# python3 -m loadtests.run telemetry-query --threads 10 --iterations 50
|
|
# python3 -m loadtests.run soak --devices 50 --rate 1 --duration 3600 --slice-sec 300
|
|
#
|
|
# Общие ограничения:
|
|
# - на устройство максимум ~900 сообщений за сценарий (API отдаёт ≤1000 строк);
|
|
# - тест создаёт СВОИ устройства (namespace lt_*) и удаляет их при IOT_CLEANUP=1.
|
|
import argparse
|
|
import json
|
|
|
|
from . import scenarios
|
|
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser(prog="loadtests")
|
|
sub = p.add_subparsers(dest="scenario", required=True)
|
|
|
|
def common(sp):
|
|
sp.add_argument("--devices", type=int, default=50)
|
|
sp.add_argument("--rate", type=float, default=1.0)
|
|
sp.add_argument("--duration", type=float, default=60.0)
|
|
sp.add_argument("--qos", type=int, choices=[0, 1], default=0)
|
|
sp.add_argument("--payload-size", type=int, default=128)
|
|
sp.add_argument("--reconnect-every", type=float, default=0.0)
|
|
|
|
s = sub.add_parser("baseline", help="равномерная нагрузка N устройств")
|
|
common(s)
|
|
|
|
s = sub.add_parser("burst", help="всплеск: тихо → пик → тихо, замер recovery")
|
|
common(s)
|
|
s.add_argument("--burst-mult", type=float, default=10.0)
|
|
|
|
s = sub.add_parser("large-payload", help="крупные payload (до ~900KB)")
|
|
common(s)
|
|
|
|
s = sub.add_parser("reconnect-storm", help="периодические разрывы соединений")
|
|
common(s)
|
|
s.set_defaults(reconnect_every=30, qos=1)
|
|
|
|
s = sub.add_parser("multitenant", help="много namespace, задержка первого сообщения")
|
|
s.add_argument("--tenants", type=int, default=20)
|
|
s.add_argument("--devices-per-tenant", type=int, default=3)
|
|
s.add_argument("--rate", type=float, default=0.2)
|
|
s.add_argument("--duration", type=float, default=60.0)
|
|
s.add_argument("--qos", type=int, choices=[0, 1], default=0)
|
|
|
|
sub.add_parser("acl-violation", help="публикация в чужой топик → отказ")
|
|
|
|
sub.add_parser("auth-neg", help="неверные креды → CONNACK 4/5")
|
|
|
|
s = sub.add_parser("api-crud", help="нагрузка на CRUD устройств")
|
|
s.add_argument("--threads", type=int, default=10)
|
|
s.add_argument("--iterations", type=int, default=20)
|
|
|
|
s = sub.add_parser("telemetry-query", help="нагрузка на чтение телеметрии")
|
|
s.add_argument("--threads", type=int, default=10)
|
|
s.add_argument("--iterations", type=int, default=50)
|
|
s.add_argument("--query-limit", type=int, default=100)
|
|
s.add_argument("--devices", type=int, default=10)
|
|
|
|
s = sub.add_parser("soak", help="длительный прогон со срезами")
|
|
common(s)
|
|
s.add_argument("--slice-sec", type=int, default=300)
|
|
|
|
args = p.parse_args()
|
|
fn = getattr(scenarios, args.scenario.replace("-", "_"))
|
|
report = fn(args)
|
|
print(json.dumps(report, ensure_ascii=False, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|