122 lines
4.4 KiB
JavaScript
122 lines
4.4 KiB
JavaScript
/**
|
|
* EN: k6 load test — Ads tracking event ingestion (POST /api/v1/tracking/events).
|
|
* VI: k6 load test — nhập event tracking quảng cáo (POST /api/v1/tracking/events).
|
|
*
|
|
* EN: Ads tracking is a high-throughput, fire-and-forget endpoint.
|
|
* VI: Tracking là endpoint thông lượng cao, fire-and-forget.
|
|
*
|
|
* Usage:
|
|
* k6 run tests/load/k6/ads-tracking.js
|
|
* k6 run --env BASE_URL=http://api.staging.goodgo.vn tests/load/k6/ads-tracking.js
|
|
*
|
|
* Thresholds:
|
|
* - 95th-percentile response time < 100ms
|
|
* - Error rate < 0.1%
|
|
* - Throughput > 500 req/s
|
|
*/
|
|
import http from 'k6/http';
|
|
import { check, sleep } from 'k6';
|
|
import { Rate, Trend, Counter } from 'k6/metrics';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Custom metrics
|
|
// ---------------------------------------------------------------------------
|
|
const trackingErrors = new Rate('tracking_errors');
|
|
const trackingDuration = new Trend('tracking_duration', true);
|
|
const eventsIngested = new Counter('events_ingested');
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test options — simulate high-frequency event stream
|
|
// ---------------------------------------------------------------------------
|
|
export const options = {
|
|
stages: [
|
|
{ duration: '20s', target: 100 },
|
|
{ duration: '1m', target: 300 },
|
|
{ duration: '30s', target: 500 }, // EN: Peak throughput / VI: Đỉnh thông lượng
|
|
{ duration: '20s', target: 0 },
|
|
],
|
|
thresholds: {
|
|
// EN: Tracking must be very fast — p95 < 100ms / VI: Tracking phải rất nhanh
|
|
http_req_duration: ['p(95)<100', 'p(99)<200'],
|
|
tracking_errors: ['rate<0.001'],
|
|
tracking_duration: ['p(95)<100'],
|
|
},
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Config
|
|
// ---------------------------------------------------------------------------
|
|
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5080';
|
|
const API_KEY = __ENV.TRACKING_API_KEY || 'test-tracking-key';
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'X-Api-Key': API_KEY,
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Event types
|
|
// ---------------------------------------------------------------------------
|
|
const EVENT_TYPES = ['impression', 'click', 'view', 'conversion', 'engagement'];
|
|
const AD_IDS = [
|
|
'00000000-0000-0000-0000-000000000011',
|
|
'00000000-0000-0000-0000-000000000012',
|
|
'00000000-0000-0000-0000-000000000013',
|
|
];
|
|
const CAMPAIGN_IDS = [
|
|
'00000000-0000-0000-0000-000000000021',
|
|
'00000000-0000-0000-0000-000000000022',
|
|
];
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helper — build a tracking event payload
|
|
// ---------------------------------------------------------------------------
|
|
function buildTrackingEvent() {
|
|
const eventType = EVENT_TYPES[Math.floor(Math.random() * EVENT_TYPES.length)];
|
|
const adId = AD_IDS[Math.floor(Math.random() * AD_IDS.length)];
|
|
const campaignId = CAMPAIGN_IDS[Math.floor(Math.random() * CAMPAIGN_IDS.length)];
|
|
|
|
return JSON.stringify({
|
|
eventType,
|
|
adId,
|
|
campaignId,
|
|
sessionId: `sess-${Math.random().toString(36).substring(2, 10)}`,
|
|
userId: Math.random() > 0.3 ? `user-${Math.floor(Math.random() * 10000)}` : null,
|
|
deviceType: ['mobile', 'desktop', 'tablet'][Math.floor(Math.random() * 3)],
|
|
platform: ['ios', 'android', 'web'][Math.floor(Math.random() * 3)],
|
|
timestamp: new Date().toISOString(),
|
|
metadata: {
|
|
pageUrl: '/pos/menu',
|
|
referrer: 'organic',
|
|
duration: eventType === 'view' ? Math.floor(Math.random() * 10000) : null,
|
|
},
|
|
});
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Default function
|
|
// ---------------------------------------------------------------------------
|
|
export default function () {
|
|
const payload = buildTrackingEvent();
|
|
|
|
const res = http.post(`${BASE_URL}/api/v1/tracking/events`, payload, { headers });
|
|
|
|
trackingDuration.add(res.timings.duration);
|
|
|
|
const ok = check(res, {
|
|
// EN: 202 Accepted or 200 OK / VI: 202 Accepted hoặc 200 OK
|
|
'status 200 or 202': (r) => r.status === 200 || r.status === 202,
|
|
'response < 100ms': (r) => r.timings.duration < 100,
|
|
});
|
|
|
|
if (ok) {
|
|
eventsIngested.add(1);
|
|
trackingErrors.add(0);
|
|
} else {
|
|
trackingErrors.add(1);
|
|
}
|
|
|
|
// EN: No sleep — fire-and-forget high throughput / VI: Không sleep — thông lượng cao
|
|
sleep(0.01);
|
|
}
|