// k6 load test simulating realistic e-commerce traffic for 5 shoppers. // // Each VU plays one shopper with a stable userId + anonymousId. Per iteration // the shopper fires a random Segment-spec event from a small catalog // (Product Viewed / Product Added / Order Completed), then "thinks" for a // short while before the next action. // // Usage: // brew install k6 // k6 run tests/k6/track.js // // Overrides: // k6 run -e WRITE_KEY=xxx -e BASE=http://localhost:3049 \ // -e VUS=5 -e DURATION=2m tests/k6/track.js import http from 'k6/http'; import { check, sleep } from 'k6'; import { randomItem, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; import encoding from 'k6/encoding'; const BASE = __ENV.BASE ?? 'http://localhost:3049'; const WRITE_KEY = __ENV.WRITE_KEY ?? 'cdp_dev_writekey_1234567890'; const VUS = parseInt(__ENV.VUS ?? '5', 10); const DURATION = __ENV.DURATION ?? '1m'; const AUTH = 'Basic ' + encoding.b64encode(`${WRITE_KEY}:`); export const options = { scenarios: { shoppers: { executor: 'constant-vus', vus: VUS, duration: DURATION, }, }, thresholds: { http_req_failed: ['rate<0.01'], http_req_duration: ['p(95)<500', 'p(99)<1500'], checks: ['rate>0.99'], }, }; // --------------------------------------------------------------------------- // Fixtures // --------------------------------------------------------------------------- const SHOPPERS = [ { user_id: 'u_001', email: 'alice@example.com', plan: 'pro', country: 'US' }, { user_id: 'u_002', email: 'bob@example.com', plan: 'free', country: 'VN' }, { user_id: 'u_003', email: 'charlie@example.com', plan: 'pro', country: 'GB' }, { user_id: 'u_004', email: 'dana@example.com', plan: 'free', country: 'SG' }, { user_id: 'u_005', email: 'eric@example.com', plan: 'team', country: 'JP' }, ]; const PRODUCTS = [ { id: 'sku_alpha', name: 'Alpha Hoodie', category: 'apparel', brand: 'CDP', price: 49.0 }, { id: 'sku_beta', name: 'Beta Mug', category: 'drinkware', brand: 'CDP', price: 12.5 }, { id: 'sku_gamma', name: 'Gamma Backpack', category: 'bags', brand: 'CDP', price: 89.0 }, { id: 'sku_delta', name: 'Delta Sneakers', category: 'footwear', brand: 'Athleta', price: 129.0 }, { id: 'sku_eps', name: 'Epsilon Headset', category: 'electronics',brand: 'Sonix', price: 199.0 }, ]; const EVENT_KINDS = ['Product Viewed', 'Product Added', 'Order Completed']; // --------------------------------------------------------------------------- // Per-iteration // --------------------------------------------------------------------------- export default function () { // Stable per-VU identity. __VU starts at 1. const shopper = SHOPPERS[(__VU - 1) % SHOPPERS.length]; const anonymousId = `anon_${shopper.user_id}`; const eventName = randomItem(EVENT_KINDS); let properties; switch (eventName) { case 'Product Viewed': properties = productProps(randomItem(PRODUCTS)); break; case 'Product Added': properties = { ...productProps(randomItem(PRODUCTS)), quantity: randomIntBetween(1, 3), }; break; case 'Order Completed': properties = orderProps(); break; } const now = new Date().toISOString(); const messageId = `k6_${shopper.user_id}_${__ITER}_${Date.now()}`; const payload = JSON.stringify({ type: 'track', messageId, userId: shopper.user_id, anonymousId, event: eventName, properties, traits: { email: shopper.email, plan: shopper.plan, country: shopper.country, }, timestamp: now, sentAt: now, context: { library_name: 'k6-ecommerce-sim', library_version: '0.2.0', ip: '127.0.0.1', userAgent: 'k6/loadtest', locale: 'en-US', page: { path: '/checkout', host: 'shop.example.com', title: 'Shop', url: 'https://shop.example.com/checkout', }, }, }); const res = http.post(`${BASE}/v1/track`, payload, { headers: { 'Content-Type': 'application/json', Authorization: AUTH, }, tags: { event: eventName }, }); check(res, { 'status 200': (r) => r.status === 200, 'body ok': (r) => r.json('ok') === true, 'fast (<500ms)': (r) => r.timings.duration < 500, }); // Think time -- a real shopper does not click 100x/sec. sleep(randomIntBetween(1, 4)); } // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function productProps(p) { return { product_id: p.id, sku: p.id, name: p.name, category: p.category, brand: p.brand, price: p.price, currency: 'USD', }; } function orderProps() { // 1 - 3 line items const lines = []; const n = randomIntBetween(1, 3); let total = 0; for (let i = 0; i < n; i++) { const p = randomItem(PRODUCTS); const qty = randomIntBetween(1, 2); total += p.price * qty; lines.push({ product_id: p.id, sku: p.id, name: p.name, price: p.price, quantity: qty, }); } return { order_id: `ord_${Date.now()}_${randomIntBetween(1000, 9999)}`, revenue: Number(total.toFixed(2)), currency: 'USD', tax: Number((total * 0.08).toFixed(2)), shipping: 5, total: Number((total + total * 0.08 + 5).toFixed(2)), products: lines, }; }