chore: add comprehensive error logging to simulation

This commit is contained in:
Hamza-Ayed
2026-07-18 22:07:47 +03:00
parent e2a472356c
commit 7a0372b018
+107 -88
View File
@@ -2,7 +2,6 @@ import readline from 'readline';
import { io } from 'socket.io-client'; import { io } from 'socket.io-client';
const API_URL = process.env.API_URL || 'http://localhost:4010/api'; const API_URL = process.env.API_URL || 'http://localhost:4010/api';
// slug المستأجر — «siro» هو المزروع على السيرفر (راجع لوق [Seed] عند الإقلاع).
const TENANT_ID = process.env.TENANT_ID || 'siro'; const TENANT_ID = process.env.TENANT_ID || 'siro';
async function api(method, path, body = null, token = null) { async function api(method, path, body = null, token = null) {
@@ -15,127 +14,147 @@ async function api(method, path, body = null, token = null) {
} }
}; };
if (token) { if (token) options.headers['Authorization'] = `Bearer ${token}`;
options.headers['Authorization'] = `Bearer ${token}`; if (body) options.body = JSON.stringify(body);
}
if (body) {
options.body = JSON.stringify(body);
}
const res = await fetch(`${API_URL}${path}`, options); const res = await fetch(`${API_URL}${path}`, options);
const data = await res.json().catch(() => null); const data = await res.json().catch(() => null);
if (!res.ok) { if (!res.ok) {
console.error(`\x1b[31m[API Error] ${method} ${path} -> ${res.status}\x1b[0m`, data); console.error(`\n\x1b[31m[API Error] ${method} ${path} -> ${res.status}\x1b[0m`);
console.error(JSON.stringify(data, null, 2));
throw new Error(`API Error: ${res.status}`); throw new Error(`API Error: ${res.status}`);
} }
return data; return data;
} }
async function run() { async function run() {
console.log('\n=========================================='); try {
console.log('🚀 Tripz Backend Automated E2E Simulation'); console.log('\n==========================================');
console.log('==========================================\n'); console.log('🚀 Tripz Backend Automated E2E Simulation');
console.log('==========================================\n');
// 1. Authenticate Demo Driver // 1. Authenticate Demo Driver
const driverPhone = '+962790000001'; const driverPhone = '+962790000001';
console.log(`[Driver] Authenticating Demo Driver (${driverPhone})...`); console.log(`[Driver] Authenticating Demo Driver (${driverPhone})...`);
await api('POST', '/auth/send-otp', { phone: driverPhone }); await api('POST', '/auth/send-otp', { phone: driverPhone });
const driverAuth = await api('POST', '/auth/verify-otp', { phone: driverPhone, code: '1234' }); const driverAuth = await api('POST', '/auth/verify-otp', { phone: driverPhone, code: '1234' });
const driverToken = driverAuth.access_token; const driverToken = driverAuth.access_token;
console.log('\x1b[32m[Driver] Authenticated successfully!\x1b[0m\n'); console.log('\x1b[32m[Driver] Authenticated successfully!\x1b[0m\n');
// 2. Authenticate Demo Rider // 2. Authenticate Demo Rider
const riderPhone = '+962790000002'; const riderPhone = '+962790000002';
console.log(`[Rider] Authenticating Demo Rider (${riderPhone})...`); console.log(`[Rider] Authenticating Demo Rider (${riderPhone})...`);
await api('POST', '/auth/send-otp', { phone: riderPhone }); await api('POST', '/auth/send-otp', { phone: riderPhone });
const riderAuth = await api('POST', '/auth/verify-otp', { phone: riderPhone, code: '1234' }); const riderAuth = await api('POST', '/auth/verify-otp', { phone: riderPhone, code: '1234' });
const riderToken = riderAuth.access_token; const riderToken = riderAuth.access_token;
console.log('\x1b[32m[Rider] Authenticated successfully!\x1b[0m\n'); console.log('\x1b[32m[Rider] Authenticated successfully!\x1b[0m\n');
// 3. Setup Driver Profile & Go Online // 3. Setup Driver Profile & Go Online
console.log(`[Driver] Creating Driver profile...`); console.log(`[Driver] Creating Driver profile...`);
await api('POST', '/drivers/apply', { service_class: 'economy', vehicle_make: 'Toyota', vehicle_model: 'Prius', vehicle_plate: '12-3456' }, driverToken); await api('POST', '/drivers/apply', { service_class: 'economy', vehicle_make: 'Toyota', vehicle_model: 'Prius', vehicle_plate: '12-3456' }, driverToken);
console.log(`[Driver] Going Online...`); console.log(`[Driver] Going Online...`);
await api('PATCH', '/drivers/status', { online: true }, driverToken); await api('PATCH', '/drivers/status', { online: true }, driverToken);
console.log('\x1b[32m[Driver] Profile created and is now ONLINE.\x1b[0m\n'); console.log('\x1b[32m[Driver] Profile created and is now ONLINE.\x1b[0m\n');
// 4. Connect WebSockets // 4. Connect WebSockets
console.log(`[Sockets] Connecting Rider and Driver via WebSockets...`); console.log(`[Sockets] Connecting Rider and Driver via WebSockets...`);
const WS_URL = API_URL.replace('/api', ''); const WS_URL = API_URL.replace('/api', '');
const driverSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${driverToken}` } }); const driverSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${driverToken}` } });
const riderSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${riderToken}` } }); const riderSocket = io(WS_URL, { extraHeaders: { Authorization: `Bearer ${riderToken}` } });
let tripId = null; let tripId = null;
driverSocket.on('connect', () => console.log('\x1b[36m[Driver WS] Connected to Gateway\x1b[0m')); // Sockets Error Logging
riderSocket.on('connect', () => console.log('\x1b[36m[Rider WS] Connected to Gateway\x1b[0m')); driverSocket.on('connect_error', (err) => console.error(`\x1b[31m[Driver WS] Error: ${err.message}\x1b[0m`));
riderSocket.on('connect_error', (err) => console.error(`\x1b[31m[Rider WS] Error: ${err.message}\x1b[0m`));
driverSocket.on('trip:dispatch', async (data) => { driverSocket.on('connect', () => console.log('\x1b[36m[Driver WS] Connected to Gateway\x1b[0m'));
console.log(`\n\x1b[35m[Driver WS] 🔔 RECEIVED DISPATCH for Trip ${data.id}!\x1b[0m`); riderSocket.on('connect', () => console.log('\x1b[36m[Rider WS] Connected to Gateway\x1b[0m'));
tripId = data.id;
console.log(`[Driver] Accepting Trip...`); driverSocket.on('trip:dispatch', async (data) => {
await api('POST', `/trips/${tripId}/accept`, null, driverToken); console.log(`\n\x1b[35m[Driver WS] 🔔 RECEIVED DISPATCH for Trip ${data.tripId || data.id}!\x1b[0m`);
console.log(`\x1b[32m[Driver] Trip Accepted successfully!\x1b[0m`); console.log(`Dispatch Payload:`, JSON.stringify(data, null, 2));
}); tripId = data.tripId || data.id;
riderSocket.on('trip:updated', (data) => { try {
console.log(`\x1b[33m[Rider WS] Trip status updated: ${data.status}\x1b[0m`); console.log(`[Driver] Accepting Trip...`);
}); await api('POST', `/trips/${tripId}/accept`, null, driverToken);
console.log(`\x1b[32m[Driver] Trip Accepted successfully!\x1b[0m`);
} catch (err) {
console.error(`\x1b[31m[Driver] Failed to accept trip!\x1b[0m`);
}
});
await new Promise(r => setTimeout(r, 2000)); riderSocket.on('trip:updated', (data) => {
console.log(`\x1b[33m[Rider WS] Trip status updated: ${data.status}\x1b[0m`);
});
// 5. Driver Location Pings await new Promise(r => setTimeout(r, 2000));
let driverLat = 32.0645; // Zarqa Coordinates
let driverLng = 36.0827;
const locationInterval = setInterval(() => { // 5. Driver Location Pings
// Driver moves slightly let driverLat = 32.0645;
driverLat += 0.0001; let driverLng = 36.0827;
const locationInterval = setInterval(() => {
driverLat += 0.0001;
driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 });
console.log(`[Driver WS] 📍 Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`);
}, 3000);
// Send first ping IMMEDIATELY
driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 }); driverSocket.emit('driver:location', { lat: driverLat, lng: driverLng, speed: 40, heading: 90 });
console.log(`[Driver WS] 📍 Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`); console.log(`[Driver WS] 📍 Initial Location ping: ${driverLat.toFixed(5)}, ${driverLng.toFixed(5)}`);
}, 3000);
// 6. Rider Requests Trip // Wait for the server to process the location update into Redis
console.log(`\n[Rider] Requesting Trip from Zarqa...`); await new Promise(r => setTimeout(r, 1500));
const tripRequest = await api('POST', '/trips', {
city: 'amman',
service_class: 'economy',
origin: { lat: 32.0650, lng: 36.0830 }, // Zarqa origin
destination: { lat: 32.0700, lng: 36.0900 }
}, riderToken);
console.log(`\x1b[32m[Rider] Trip created: ${tripRequest.trip.id}\x1b[0m`); // 6. Rider Requests Trip
console.log(`\n[Rider] Requesting Trip from Zarqa...`);
const tripRequest = await api('POST', '/trips', {
city: 'amman',
service_class: 'economy',
origin: { lat: 32.0650, lng: 36.0830 },
destination: { lat: 32.0700, lng: 36.0900 }
}, riderToken);
// 7. Simulate Trip Flow (Wait 10 seconds per state) console.log(`\x1b[32m[Rider] Trip created: ${tripRequest.trip?.id || tripRequest.id}\x1b[0m`);
await new Promise(r => setTimeout(r, 10000)); console.log(`[System] Offered to \x1b[33m${tripRequest.offeredDrivers}\x1b[0m drivers nearby.`);
if (tripId) { // 7. Simulate Trip Flow
console.log(`\n[Driver] Arriving at pickup...`); await new Promise(r => setTimeout(r, 10000));
await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, driverToken);
await new Promise(r => setTimeout(r, 5000)); if (tripId) {
try {
console.log(`\n[Driver] Arriving at pickup...`);
await api('PATCH', `/trips/${tripId}/status`, { status: 'driver_arrived' }, driverToken);
await new Promise(r => setTimeout(r, 5000));
console.log(`\n[Driver] Starting Trip...`); console.log(`\n[Driver] Starting Trip...`);
await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, driverToken); await api('PATCH', `/trips/${tripId}/status`, { status: 'in_progress' }, driverToken);
await new Promise(r => setTimeout(r, 5000));
await new Promise(r => setTimeout(r, 5000)); console.log(`\n[Driver] Completing Trip...`);
await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, driverToken);
console.log(`\n[Driver] Completing Trip...`); console.log(`\n\x1b[32m🎉 E2E Simulation Completed Successfully!\x1b[0m\n`);
await api('PATCH', `/trips/${tripId}/status`, { status: 'completed' }, driverToken); } catch(e) {
console.error(`\x1b[31m[Simulation Error] ${e.message}\x1b[0m`);
}
} else {
console.log(`\n\x1b[31mFailed to receive dispatch!\x1b[0m`);
console.log(`[Hint] Check if offeredDrivers was 0. If it was 0, the backend didn't find the driver in Redis. If it was > 0, the backend emitted the socket event but the driver didn't receive it.\n`);
}
console.log(`\n\x1b[32m🎉 E2E Simulation Completed Successfully!\x1b[0m\n`); clearInterval(locationInterval);
} else { driverSocket.disconnect();
console.log(`\n\x1b[31mFailed to receive dispatch!\x1b[0m\n`); riderSocket.disconnect();
process.exit(0);
} catch (error) {
console.error(`\n\x1b[31m[Fatal Error] Simulation Crashed: ${error.message}\x1b[0m\n`);
process.exit(1);
} }
clearInterval(locationInterval);
driverSocket.disconnect();
riderSocket.disconnect();
process.exit(0);
} }
run().catch(console.error); run();