SPB Git forge

spb/spinza

Public
8commits 1branches 0releases
1.6 MBsize
maindefault branch
16 days agolast push
TypeScript 97.6% SQL 1.4% JavaScript 0.5%
2.4 KB · 55 lines javascript
Raw Blame History
1/**2 * k6 load test — concurrent players spinning.3 *   k6 run -e BASE=https://www.spinza.dev -e VUS=100 -e DURATION=60s qa/load/spin.k6.js4 * Each VU registers a throwaway account (username lt_<vu>_<rand>) and spins on neon-vault.5 * Never run against production without lowering the register rate limit awareness (10/10 min per IP):6 * use -e USERS_FILE with pre-created "username:password" lines to skip registration.7 */8import http from "k6/http";9import { check, sleep } from "k6";10import { uuidv4 } from "https://jslib.k6.io/k6-utils/1.4.0/index.js";1112const BASE = __ENV.BASE || "http://localhost:8230";13export const options = {14  scenarios: {15    spins: { executor: "constant-vus", vus: Number(__ENV.VUS || 50), duration: __ENV.DURATION || "60s" },16  },17  thresholds: {18    http_req_failed: ["rate<0.01"],19    "http_req_duration{name:spin}": ["p(95)<250"],20  },21};2223export function setup() {24  const users = [];25  if (__ENV.USERS_FILE) {26    for (const line of open(__ENV.USERS_FILE).split("\n")) {27      const [u, p] = line.trim().split(":");28      if (u && p) users.push({ username: u, password: p });29    }30  }31  return { users };32}3334export default function (data) {35  const jar = http.cookieJar();36  let creds = data.users.length ? data.users[(__VU - 1) % data.users.length] : null;37  if (!creds) {38    creds = { username: `lt_${__VU}_${Math.floor(Math.random() * 1e6)}`.slice(0, 24), password: "loadtest-pass-123" };39    const r = http.post(`${BASE}/api/auth/register`, JSON.stringify({ ...creds, confirmPassword: creds.password, ageConfirmed: true }), { headers: { "Content-Type": "application/json", Origin: BASE }, tags: { name: "register" } });40    check(r, { registered: (res) => res.status === 200 });41  } else {42    const r = http.post(`${BASE}/api/auth/login`, JSON.stringify(creds), { headers: { "Content-Type": "application/json", Origin: BASE }, tags: { name: "login" } });43    check(r, { logged_in: (res) => res.status === 200 });44  }45  for (let i = 0; i < 40; i++) {46    const r = http.post(`${BASE}/api/games/neon-vault/spin`, JSON.stringify({ bet: 10, clientRoundId: uuidv4() }), { headers: { "Content-Type": "application/json", Origin: BASE }, tags: { name: "spin" } });47    check(r, { spin_ok: (res) => res.status === 200 || res.status === 402 });48    if (r.status === 402) {49      http.post(`${BASE}/api/rewards/rescue/claim`, null, { headers: { Origin: BASE }, tags: { name: "rescue" } });50    }51    sleep(0.3);52  }53  void jar;54}55