From 1f57b642c3a396d09c0ef676822da49916e06c66 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Fri, 17 Jul 2026 00:17:59 +0300 Subject: [PATCH] Update: 2026-07-17 00:17:59 --- stress_test/load_test.js | 128 ++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 42 deletions(-) diff --git a/stress_test/load_test.js b/stress_test/load_test.js index 6eb10ebc..4498b452 100644 --- a/stress_test/load_test.js +++ b/stress_test/load_test.js @@ -33,39 +33,60 @@ function getMockDriverJwt(driverId) { const jsonString = output.substring(output.indexOf('{')); return JSON.parse(jsonString).jwt; } catch (err) { - console.error(`Failed to generate JWT for driver ${driverId}`, err.message); + console.error(`[Error] Failed to generate JWT for driver ${driverId}`, err.message); return 'mock_jwt'; } } +let metrics = { + successful: 0, + failed: 0, + connectionErrors: 0, + apiErrors: 0, + totalTime: 0 +}; + async function simulateTrip(tripIndex) { const driverId = 900000 + tripIndex; const passengerId = 800000 + tripIndex; const driverJwt = getMockDriverJwt(driverId); - console.log(`[Trip ${tripIndex}] Starting simulation... Driver: ${driverId}, Passenger: ${passengerId}`); + console.log(`[Trip ${tripIndex}] Starting... Driver: ${driverId}, Passenger: ${passengerId}`); + const tripStartTime = Date.now(); // 1. Connect Driver to Socket - const socket = io(argv.socketUrl, { + // Note: socket.io usually expects http:// URL for the initial connection, even for websockets + const socketUrl = argv.socketUrl.replace('ws://', 'http://').replace('wss://', 'https://'); + const socket = io(socketUrl, { query: { driver_id: driverId, platform: 'android', jwt: driverJwt }, - transports: ['websocket'] + transports: ['websocket'], + reconnection: false, + timeout: 5000 }); return new Promise((resolve, reject) => { let rideId = null; + socket.on('connect_error', (err) => { + console.error(`[Trip ${tripIndex}] Socket Connection Error: ${err.message}. Is the Location Server running on ${socketUrl}?`); + metrics.connectionErrors++; + metrics.failed++; + socket.disconnect(); + resolve(false); + }); + socket.on('connect', async () => { - console.log(`[Trip ${tripIndex}] Driver ${driverId} connected to socket.`); + console.log(`[Trip ${tripIndex}] Driver connected to socket.`); // 2. Passenger Requests Ride try { const addRideFormData = new URLSearchParams({ passenger_id: passengerId, - start_location: '31.95,35.91', // Amman + start_location: '31.95,35.91', end_location: '31.96,35.92', price: '5', price_token: 'dummy', @@ -78,22 +99,24 @@ async function simulateTrip(tripIndex) { }); const reqStart = Date.now(); - const res = await axios.post(`${argv.baseUrl}/ride/rides/add_ride.php`, addRideFormData.toString(), { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + await axios.post(`${argv.baseUrl}/ride/rides/add_ride.php`, addRideFormData.toString(), { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + timeout: 5000 }); - // Note: the backend add_ride.php might return the newly created ride ID - console.log(`[Trip ${tripIndex}] Passenger requested ride. Response time: ${Date.now() - reqStart}ms`); + console.log(`[Trip ${tripIndex}] Passenger requested ride. (API Latency: ${Date.now() - reqStart}ms)`); } catch (err) { - console.error(`[Trip ${tripIndex}] Error requesting ride:`, err.message); + console.error(`[Trip ${tripIndex}] API Error requesting ride:`, err.message); + metrics.apiErrors++; + metrics.failed++; socket.disconnect(); - return reject(err); + return resolve(false); } }); socket.on('market_new_ride', async (payload) => { rideId = payload.id; - console.log(`[Trip ${tripIndex}] Driver ${driverId} received ride offer #${rideId}. Accepting...`); + console.log(`[Trip ${tripIndex}] Received ride offer #${rideId}. Accepting...`); // 3. Driver Accepts Ride try { @@ -105,9 +128,10 @@ async function simulateTrip(tripIndex) { const acceptStart = Date.now(); await axios.post(`${argv.baseUrl}/ride/rides/acceptRide.php`, acceptFormData.toString(), { - headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + timeout: 5000 }); - console.log(`[Trip ${tripIndex}] Driver ${driverId} accepted ride #${rideId}. Response time: ${Date.now() - acceptStart}ms`); + console.log(`[Trip ${tripIndex}] Accepted ride #${rideId}. (API Latency: ${Date.now() - acceptStart}ms)`); // 4. Simulate Driving (Updates Location) let steps = 0; @@ -122,60 +146,80 @@ async function simulateTrip(tripIndex) { }); if (steps === 3) { - // Driver Arrived / Starts Ride - const startFormData = new URLSearchParams({ - id: rideId, - driver_id: driverId, - status: 'start' - }); + const startFormData = new URLSearchParams({ id: rideId, driver_id: driverId, status: 'start' }); await axios.post(`${argv.baseUrl}/ride/rides/start_ride.php`, startFormData.toString()); - console.log(`[Trip ${tripIndex}] Driver ${driverId} started ride #${rideId}`); + console.log(`[Trip ${tripIndex}] Started ride #${rideId}`); } if (steps === 6) { clearInterval(driveInterval); // 5. Finish Ride - const finishFormData = new URLSearchParams({ - id: rideId, - driver_id: driverId, - status: 'finish' - }); + const finishFormData = new URLSearchParams({ id: rideId, driver_id: driverId, status: 'finish' }); await axios.post(`${argv.baseUrl}/ride/rides/finish_ride_updates.php`, finishFormData.toString()); - console.log(`[Trip ${tripIndex}] Driver ${driverId} finished ride #${rideId}.`); + console.log(`[Trip ${tripIndex}] Finished ride #${rideId}.`); socket.disconnect(); - resolve(`Trip ${tripIndex} completed successfully.`); + metrics.successful++; + resolve(true); } - }, 1000); + }, 1000); // 1-second interval to simulate fast movement } catch (err) { - console.error(`[Trip ${tripIndex}] Error during ride execution:`, err.message); + console.error(`[Trip ${tripIndex}] API Error during ride execution:`, err.message); + metrics.apiErrors++; + metrics.failed++; socket.disconnect(); - reject(err); + resolve(false); } }); - socket.on('disconnect', () => { - console.log(`[Trip ${tripIndex}] Driver ${driverId} disconnected.`); - }); + // Timeout fallback if market_new_ride never arrives + setTimeout(() => { + if (!rideId && socket.connected) { + console.error(`[Trip ${tripIndex}] Timeout: Never received 'market_new_ride' via WebSocket.`); + metrics.failed++; + socket.disconnect(); + resolve(false); + } + }, 15000); }); } async function runTest() { + console.log(`\n======================================================`); console.log(`🚀 Starting Load Test with ${argv.trips} concurrent trips`); + console.log(`📡 Backend API URL: ${argv.baseUrl}`); + console.log(`🔌 Socket URL: ${argv.socketUrl}`); + console.log(`======================================================\n`); + + const startTime = Date.now(); const promises = []; + + // Launch all simulated trips for (let i = 1; i <= argv.trips; i++) { promises.push(simulateTrip(i)); - // Add a slight stagger so we don't overwhelm immediately - await new Promise(r => setTimeout(r, 100)); + // Small delay between launches to prevent DDOSing localhost + await new Promise(r => setTimeout(r, 50)); } - try { - await Promise.all(promises); - console.log("✅ All simulated trips finished successfully."); - } catch (e) { - console.error("❌ Some trips failed.", e); + await Promise.all(promises); + + const durationSec = ((Date.now() - startTime) / 1000).toFixed(2); + const tps = (metrics.successful / durationSec).toFixed(2); + + console.log(`\n======================================================`); + console.log(`📊 STRESS TEST RESULTS:`); + console.log(`======================================================`); + console.log(`⏱️ Total Duration: ${durationSec} seconds`); + console.log(`⚡ Throughput: ${tps} trips / second`); + console.log(`✅ Successful Trips: ${metrics.successful} / ${argv.trips}`); + console.log(`❌ Failed Trips: ${metrics.failed} / ${argv.trips}`); + if (metrics.failed > 0) { + console.log(` - Socket Errors: ${metrics.connectionErrors}`); + console.log(` - HTTP API Errors: ${metrics.apiErrors}`); } + console.log(`======================================================\n`); + process.exit(0); } runTest();