|
| 1 | +/** |
| 2 | + * K6 Fixed-Iteration Load Test: skyflow.vault().bulkInsert() [v3 SDK] |
| 3 | + * |
| 4 | + * Runs exactly TOTAL_REQUESTS iterations across all VUs, then stops. |
| 5 | + * RPS = total_requests / total_time_taken (no ramp-up/ramp-down noise) |
| 6 | + * |
| 7 | + * Run: |
| 8 | + * k6 run load-testing/k6/insert-fixed.js |
| 9 | + * k6 run --env TOTAL_REQUESTS=100000 --env VUS=200 load-testing/k6/insert-fixed.js |
| 10 | + * |
| 11 | + * Env vars: |
| 12 | + * WRAPPER_URL default: http://localhost:8080 |
| 13 | + * VUS virtual users default: 100 |
| 14 | + * TOTAL_REQUESTS total SDK calls default: 100000 |
| 15 | + * NUM_RECORDS records per call default: 1 |
| 16 | + * TABLE vault table default: load_test_table |
| 17 | + */ |
| 18 | + |
| 19 | +import http from 'k6/http'; |
| 20 | +import { check } from 'k6'; |
| 21 | +import { Rate, Trend } from 'k6/metrics'; |
| 22 | + |
| 23 | +const BASE_URL = __ENV.WRAPPER_URL || 'http://localhost:8080'; |
| 24 | +const VUS = parseInt(__ENV.VUS || '100'); |
| 25 | +const TOTAL_REQUESTS = parseInt(__ENV.TOTAL_REQUESTS || '100000'); |
| 26 | +const NUM_RECORDS = parseInt(__ENV.NUM_RECORDS || '1'); |
| 27 | +const TABLE = __ENV.TABLE || 'load_test_table'; |
| 28 | + |
| 29 | +const errorRate = new Rate('insert_errors'); |
| 30 | +const sdkDuration = new Trend('insert_sdk_duration_ms', true); |
| 31 | + |
| 32 | +export const options = { |
| 33 | + vus: VUS, |
| 34 | + iterations: TOTAL_REQUESTS, // k6 stops exactly after this many calls |
| 35 | + summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(50)', 'p(90)', 'p(95)', 'p(99)'], |
| 36 | +}; |
| 37 | + |
| 38 | +export default function () { |
| 39 | + const res = http.post( |
| 40 | + `${BASE_URL}/insert`, |
| 41 | + JSON.stringify({ table: TABLE, num_records: NUM_RECORDS }), |
| 42 | + { headers: { 'Content-Type': 'application/json' } } |
| 43 | + ); |
| 44 | + |
| 45 | + const ok = check(res, { |
| 46 | + 'status 200': (r) => r.status === 200, |
| 47 | + }); |
| 48 | + |
| 49 | + errorRate.add(!ok); |
| 50 | + sdkDuration.add(res.timings.duration); |
| 51 | +} |
| 52 | + |
| 53 | +export function setup() { |
| 54 | + http.post(`${BASE_URL}/reset`); // clear counters so RPS is correct for this run |
| 55 | +} |
| 56 | + |
| 57 | +export function teardown() { |
| 58 | + const res = http.get(`${BASE_URL}/metrics`); |
| 59 | + if (res.status === 200) console.log('[WrapperMetrics]', res.body); |
| 60 | +} |
| 61 | + |
| 62 | +export function handleSummary(data) { |
| 63 | + const reqs = data.metrics['http_reqs']; |
| 64 | + const dur = data.metrics['http_req_duration']; |
| 65 | + const failed = data.metrics['http_req_failed']; |
| 66 | + const sdkDur = data.metrics['insert_sdk_duration_ms']; |
| 67 | + |
| 68 | + const totalReqs = reqs?.values?.count ?? 0; |
| 69 | + const testDurationMs = data?.state?.testRunDurationMs ?? 0; |
| 70 | + const testDurationSec = (testDurationMs / 1000).toFixed(3); |
| 71 | + |
| 72 | + // RPS = total_requests / total_time_taken (what the user asked for) |
| 73 | + const rpsRaw = totalReqs > 0 && testDurationMs > 0 |
| 74 | + ? totalReqs / (testDurationMs / 1000) |
| 75 | + : 0; |
| 76 | + const rps = rpsRaw.toFixed(2); |
| 77 | + |
| 78 | + // k6's own rate (same formula, shown for cross-check) |
| 79 | + const k6RateRaw = reqs?.values?.rate ?? 0; |
| 80 | + const k6Rate = k6RateRaw.toFixed(2); |
| 81 | + |
| 82 | + // Delta between the two — should be <5% if both are correct. |
| 83 | + // Divergence happens because testRunDurationMs includes teardown() time. |
| 84 | + const delta = Math.abs(rpsRaw - k6RateRaw); |
| 85 | + const deltaPct = k6RateRaw > 0 ? ((delta / k6RateRaw) * 100).toFixed(1) : '0.0'; |
| 86 | + const match = parseFloat(deltaPct) < 5 ? 'OK (within 5%)' : 'WARN (>5% gap — check teardown latency)'; |
| 87 | + |
| 88 | + const p50 = (dur?.values?.['p(50)'] ?? 0).toFixed(1); |
| 89 | + const p95 = (dur?.values?.['p(95)'] ?? 0).toFixed(1); |
| 90 | + const p99 = (dur?.values?.['p(99)'] ?? 0).toFixed(1); |
| 91 | + const avgMs = (dur?.values?.avg ?? 0).toFixed(1); |
| 92 | + const minMs = (dur?.values?.min ?? 0).toFixed(1); |
| 93 | + const maxMs = (dur?.values?.max ?? 0).toFixed(1); |
| 94 | + const errRate = ((failed?.values?.rate ?? 0) * 100).toFixed(2); |
| 95 | + const sdkP50 = (sdkDur?.values?.['p(50)'] ?? 0).toFixed(1); |
| 96 | + const sdkP95 = (sdkDur?.values?.['p(95)'] ?? 0).toFixed(1); |
| 97 | + const sdkP99 = (sdkDur?.values?.['p(99)'] ?? 0).toFixed(1); |
| 98 | + |
| 99 | + const summary = ` |
| 100 | +╔══════════════════════════════════════════════════╗ |
| 101 | +║ FIXED-ITERATION INSERT SUMMARY ║ |
| 102 | +╠══════════════════════════════════════════════════╣ |
| 103 | +║ Config ║ |
| 104 | +║ VUs : ${String(VUS).padStart(24)} ║ |
| 105 | +║ Target requests : ${String(TOTAL_REQUESTS).padStart(24)} ║ |
| 106 | +║ Completed : ${String(totalReqs).padStart(24)} ║ |
| 107 | +║ Test duration : ${(testDurationSec + 's').padStart(24)} ║ |
| 108 | +╠══════════════════════════════════════════════════╣ |
| 109 | +║ Throughput ║ |
| 110 | +║ RPS (total/time) : ${String(rps).padStart(24)} ║ |
| 111 | +║ RPS (k6 rate) : ${String(k6Rate).padStart(24)} ║ |
| 112 | +║ Delta : ${(delta.toFixed(2) + ' (' + deltaPct + '%)').padStart(24)} ║ |
| 113 | +║ Verdict : ${String(match).padStart(24)} ║ |
| 114 | +║ Error rate : ${(errRate + '%').padStart(24)} ║ |
| 115 | +╠══════════════════════════════════════════════════╣ |
| 116 | +║ HTTP round-trip latency (ms) ║ |
| 117 | +║ min : ${String(minMs).padStart(24)} ║ |
| 118 | +║ avg : ${String(avgMs).padStart(24)} ║ |
| 119 | +║ p50 : ${String(p50).padStart(24)} ║ |
| 120 | +║ p95 : ${String(p95).padStart(24)} ║ |
| 121 | +║ p99 : ${String(p99).padStart(24)} ║ |
| 122 | +║ max : ${String(maxMs).padStart(24)} ║ |
| 123 | +╠══════════════════════════════════════════════════╣ |
| 124 | +║ SDK duration (ms) ║ |
| 125 | +║ p50 : ${String(sdkP50).padStart(24)} ║ |
| 126 | +║ p95 : ${String(sdkP95).padStart(24)} ║ |
| 127 | +║ p99 : ${String(sdkP99).padStart(24)} ║ |
| 128 | +╚══════════════════════════════════════════════════╝ |
| 129 | +`; |
| 130 | + console.log(summary); |
| 131 | + return { stdout: summary }; |
| 132 | +} |
0 commit comments