120 lines
4.2 KiB
JavaScript
120 lines
4.2 KiB
JavaScript
/**
|
||
* EN: k6 load test — Order creation endpoint (POST /api/v1/orders).
|
||
* VI: k6 load test — endpoint tạo đơn hàng (POST /api/v1/orders).
|
||
*
|
||
* Usage:
|
||
* k6 run tests/load/k6/order-creation.js
|
||
* k6 run --env BASE_URL=http://api.staging.goodgo.vn tests/load/k6/order-creation.js
|
||
*
|
||
* Thresholds:
|
||
* - 95th-percentile response time < 500ms
|
||
* - Error rate < 1%
|
||
*/
|
||
import http from 'k6/http';
|
||
import { check, sleep } from 'k6';
|
||
import { Rate, Trend } from 'k6/metrics';
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Custom metrics
|
||
// ---------------------------------------------------------------------------
|
||
const orderCreationErrors = new Rate('order_creation_errors');
|
||
const orderCreationDuration = new Trend('order_creation_duration', true);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Test options
|
||
// ---------------------------------------------------------------------------
|
||
export const options = {
|
||
stages: [
|
||
// EN: Ramp up to 20 VUs over 30s / VI: Tăng lên 20 VUs trong 30s
|
||
{ duration: '30s', target: 20 },
|
||
// EN: Hold at 20 VUs for 1 minute / VI: Duy trì 20 VUs trong 1 phút
|
||
{ duration: '1m', target: 20 },
|
||
// EN: Spike to 50 VUs for 30s / VI: Tăng đột biến lên 50 VUs trong 30s
|
||
{ duration: '30s', target: 50 },
|
||
// EN: Ramp down / VI: Giảm dần
|
||
{ duration: '30s', target: 0 },
|
||
],
|
||
thresholds: {
|
||
// EN: 95% of requests must complete below 500ms / VI: 95% requests phải hoàn thành dưới 500ms
|
||
http_req_duration: ['p(95)<500'],
|
||
// EN: Error rate must stay below 1% / VI: Tỷ lệ lỗi phải dưới 1%
|
||
order_creation_errors: ['rate<0.01'],
|
||
// EN: Custom trend threshold / VI: Ngưỡng trend tùy chỉnh
|
||
order_creation_duration: ['p(99)<1000'],
|
||
},
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Config
|
||
// ---------------------------------------------------------------------------
|
||
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5010';
|
||
const JWT_TOKEN = __ENV.JWT_TOKEN || 'test-bearer-token';
|
||
|
||
const SHOP_ID = __ENV.SHOP_ID || '00000000-0000-0000-0000-000000000001';
|
||
const PRODUCT_ID = __ENV.PRODUCT_ID || '00000000-0000-0000-0000-000000000002';
|
||
|
||
const headers = {
|
||
'Content-Type': 'application/json',
|
||
Authorization: `Bearer ${JWT_TOKEN}`,
|
||
'X-Shop-Id': SHOP_ID,
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Helper — generate a random order payload
|
||
// ---------------------------------------------------------------------------
|
||
function buildOrderPayload() {
|
||
const tableNumber = Math.floor(Math.random() * 20) + 1;
|
||
const qty = Math.floor(Math.random() * 3) + 1;
|
||
return JSON.stringify({
|
||
shopId: SHOP_ID,
|
||
tableNumber: `T${tableNumber}`,
|
||
orderType: 'dine_in',
|
||
items: [
|
||
{
|
||
productId: PRODUCT_ID,
|
||
quantity: qty,
|
||
unitPrice: 35000,
|
||
note: '',
|
||
},
|
||
],
|
||
note: `k6-load-test-${Date.now()}`,
|
||
});
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Default function — executed per VU iteration
|
||
// ---------------------------------------------------------------------------
|
||
export default function () {
|
||
const payload = buildOrderPayload();
|
||
const startTime = Date.now();
|
||
|
||
const res = http.post(`${BASE_URL}/api/v1/orders`, payload, { headers });
|
||
|
||
const duration = Date.now() - startTime;
|
||
orderCreationDuration.add(duration);
|
||
|
||
const success = check(res, {
|
||
// EN: Status is 201 Created / VI: Status là 201 Created
|
||
'status is 201': (r) => r.status === 201,
|
||
// EN: Response body has success=true / VI: Body phản hồi có success=true
|
||
'body has success:true': (r) => {
|
||
try {
|
||
return JSON.parse(r.body).success === true;
|
||
} catch {
|
||
return false;
|
||
}
|
||
},
|
||
// EN: Response time below 500ms / VI: Thời gian phản hồi dưới 500ms
|
||
'response time < 500ms': (r) => r.timings.duration < 500,
|
||
});
|
||
|
||
if (!success) {
|
||
orderCreationErrors.add(1);
|
||
} else {
|
||
orderCreationErrors.add(0);
|
||
}
|
||
|
||
// EN: Think time between requests (0.5–1.5s) / VI: Thời gian nghỉ giữa các request
|
||
sleep(0.5 + Math.random());
|
||
}
|