feat: add automated stress testing script for driver location tracking and trip lifecycle simulation

This commit is contained in:
Hamza-Ayed
2026-07-19 01:51:47 +03:00
parent e9beeb90b4
commit 7e06b1241f
+155
View File
@@ -0,0 +1,155 @@
import { io } from 'socket.io-client';
const API_URL = process.env.API_URL || 'http://localhost:4010/api';
const TENANT_ID = process.env.TENANT_ID || 'siro';
const NUM_DRIVERS = parseInt(process.env.NUM_DRIVERS || '100', 10);
const TRIP_RATE_SEC = parseInt(process.env.TRIP_RATE_SEC || '2', 10);
const DRIVER_PING_INTERVAL_MS = parseInt(process.env.DRIVER_PING_INTERVAL_MS || '3000', 10);
async function api(method, path, body = null, token = null) {
const options = {
method,
headers: {
'Content-Type': 'application/json',
'x-tenant-id': TENANT_ID,
'x-device-id': 'stress-test-device'
}
};
if (token) options.headers['Authorization'] = `Bearer ${token}`;
if (body) options.body = JSON.stringify(body);
const res = await fetch(`${API_URL}${path}`, options);
const data = await res.json().catch(() => null);
if (!res.ok) {
throw new Error(`API Error: ${method} ${path} -> ${res.status} : ${JSON.stringify(data)}`);
}
return data;
}
let drivers = [];
let reqCount = 0;
let errors = 0;
let tripsCompleted = 0;
async function setupDriver(index) {
const phone = `+96279${String(index).padStart(6, '0')}`;
try {
// Authenticate using dev bypass
const auth = await api('POST', '/auth/verify-otp', { phone, code: '1234' });
const token = auth.access_token;
// Auto-create driver profile if missing
if (!auth.user.vehicle_plate) {
await api('POST', '/drivers/apply', {
service_class: 'economy',
vehicle_make: 'Toyota',
vehicle_model: 'Corolla',
vehicle_plate: `${index}-TEST`
}, token).catch(() => {});
}
// Go online
await api('PATCH', '/drivers/status', { online: true }, token);
const WS_URL = API_URL.replace('/api', '');
const socket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${token}` }, reconnection: true });
const driverObj = { phone, token, socket, available: true };
drivers.push(driverObj);
// Initial random location in Amman
let lat = 31.95 + (Math.random() * 0.1);
let lng = 35.91 + (Math.random() * 0.1);
// Start pinging location
setInterval(() => {
lat += 0.0001; // Move slightly
socket.emit('driver:location', { lat, lng, speed: 40, heading: 90 });
reqCount++;
}, DRIVER_PING_INTERVAL_MS);
// Listen for trip offers
socket.on('trip:offer', async (data) => {
if (!driverObj.available) return;
driverObj.available = false;
const tripId = data.tripId || data.id;
try {
await api('POST', `/trips/${tripId}/accept`, null, token);
// Simulate trip flow timeline (shortened for stress test)
setTimeout(async () => {
await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, token).catch(()=>{});
await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, token).catch(()=>{});
await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, token).catch(()=>{});
driverObj.available = true; // Free to take next trip
tripsCompleted++;
}, 5000);
} catch (err) {
driverObj.available = true;
}
});
} catch (err) {
errors++;
}
}
async function spawnRiderAndRequestTrip(index) {
const phone = `+96278${String(index).padStart(6, '0')}`;
try {
const auth = await api('POST', '/auth/verify-otp', { phone, code: '1234' });
const token = auth.access_token;
// Pick a location roughly where drivers are spawned
const lat = 31.95 + (Math.random() * 0.1);
const lng = 35.91 + (Math.random() * 0.1);
await api('POST', '/trips', {
city: 'amman',
service_class: 'economy',
origin: { lat, lng },
destination: { lat: lat + 0.05, lng: lng + 0.05 }
}, token);
reqCount++;
} catch (err) {
errors++;
}
}
async function start() {
console.log(`\x1b[36m==================================================\x1b[0m`);
console.log(`🚀 Starting Stress Test`);
console.log(`\x1b[33mDrivers:\x1b[0m ${NUM_DRIVERS}`);
console.log(`\x1b[33mTrips/Sec:\x1b[0m ${TRIP_RATE_SEC}`);
console.log(`\x1b[33mLocation Ping Interval:\x1b[0m ${DRIVER_PING_INTERVAL_MS}ms`);
console.log(`\x1b[36m==================================================\x1b[0m\n`);
// Throttle driver creation so we don't spam the DB at startup
for (let i = 0; i < NUM_DRIVERS; i++) {
setupDriver(i);
if (i % 10 === 0) await new Promise(r => setTimeout(r, 100));
}
console.log(`[System] Finished spawning drivers. Waiting 5s for sockets...`);
await new Promise(r => setTimeout(r, 5000));
console.log(`[System] Commencing trip requests...`);
let riderIndex = 0;
setInterval(() => {
for (let i = 0; i < TRIP_RATE_SEC; i++) {
spawnRiderAndRequestTrip(riderIndex++);
}
}, 1000);
// Monitor performance locally
setInterval(() => {
const currentRps = reqCount / 5;
console.log(`\x1b[32m[Metrics]\x1b[0m Active Drivers: ${drivers.length} | API/WS Requests/sec: ${currentRps.toFixed(1)} | Trips Completed: ${tripsCompleted} | Errors: ${errors}`);
reqCount = 0;
}, 5000);
}
start();