Update: 2026-07-17 00:17:59

This commit is contained in:
Hamza-Ayed
2026-07-17 00:17:59 +03:00
parent c5ed2099f9
commit 1f57b642c3
+86 -42
View File
@@ -33,39 +33,60 @@ function getMockDriverJwt(driverId) {
const jsonString = output.substring(output.indexOf('{')); const jsonString = output.substring(output.indexOf('{'));
return JSON.parse(jsonString).jwt; return JSON.parse(jsonString).jwt;
} catch (err) { } 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'; return 'mock_jwt';
} }
} }
let metrics = {
successful: 0,
failed: 0,
connectionErrors: 0,
apiErrors: 0,
totalTime: 0
};
async function simulateTrip(tripIndex) { async function simulateTrip(tripIndex) {
const driverId = 900000 + tripIndex; const driverId = 900000 + tripIndex;
const passengerId = 800000 + tripIndex; const passengerId = 800000 + tripIndex;
const driverJwt = getMockDriverJwt(driverId); 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 // 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: { query: {
driver_id: driverId, driver_id: driverId,
platform: 'android', platform: 'android',
jwt: driverJwt jwt: driverJwt
}, },
transports: ['websocket'] transports: ['websocket'],
reconnection: false,
timeout: 5000
}); });
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let rideId = null; 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 () => { 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 // 2. Passenger Requests Ride
try { try {
const addRideFormData = new URLSearchParams({ const addRideFormData = new URLSearchParams({
passenger_id: passengerId, passenger_id: passengerId,
start_location: '31.95,35.91', // Amman start_location: '31.95,35.91',
end_location: '31.96,35.92', end_location: '31.96,35.92',
price: '5', price: '5',
price_token: 'dummy', price_token: 'dummy',
@@ -78,22 +99,24 @@ async function simulateTrip(tripIndex) {
}); });
const reqStart = Date.now(); const reqStart = Date.now();
const res = await axios.post(`${argv.baseUrl}/ride/rides/add_ride.php`, addRideFormData.toString(), { await axios.post(`${argv.baseUrl}/ride/rides/add_ride.php`, addRideFormData.toString(), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' } 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. (API Latency: ${Date.now() - reqStart}ms)`);
console.log(`[Trip ${tripIndex}] Passenger requested ride. Response time: ${Date.now() - reqStart}ms`);
} catch (err) { } 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(); socket.disconnect();
return reject(err); return resolve(false);
} }
}); });
socket.on('market_new_ride', async (payload) => { socket.on('market_new_ride', async (payload) => {
rideId = payload.id; 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 // 3. Driver Accepts Ride
try { try {
@@ -105,9 +128,10 @@ async function simulateTrip(tripIndex) {
const acceptStart = Date.now(); const acceptStart = Date.now();
await axios.post(`${argv.baseUrl}/ride/rides/acceptRide.php`, acceptFormData.toString(), { 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) // 4. Simulate Driving (Updates Location)
let steps = 0; let steps = 0;
@@ -122,60 +146,80 @@ async function simulateTrip(tripIndex) {
}); });
if (steps === 3) { 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()); 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) { if (steps === 6) {
clearInterval(driveInterval); clearInterval(driveInterval);
// 5. Finish Ride // 5. Finish Ride
const finishFormData = new URLSearchParams({ const finishFormData = new URLSearchParams({ id: rideId, driver_id: driverId, status: 'finish' });
id: rideId,
driver_id: driverId,
status: 'finish'
});
await axios.post(`${argv.baseUrl}/ride/rides/finish_ride_updates.php`, finishFormData.toString()); 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(); socket.disconnect();
resolve(`Trip ${tripIndex} completed successfully.`); metrics.successful++;
resolve(true);
} }
}, 1000); }, 1000); // 1-second interval to simulate fast movement
} catch (err) { } 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(); socket.disconnect();
reject(err); resolve(false);
} }
}); });
socket.on('disconnect', () => { // Timeout fallback if market_new_ride never arrives
console.log(`[Trip ${tripIndex}] Driver ${driverId} disconnected.`); 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() { async function runTest() {
console.log(`\n======================================================`);
console.log(`🚀 Starting Load Test with ${argv.trips} concurrent trips`); 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 = []; const promises = [];
// Launch all simulated trips
for (let i = 1; i <= argv.trips; i++) { for (let i = 1; i <= argv.trips; i++) {
promises.push(simulateTrip(i)); promises.push(simulateTrip(i));
// Add a slight stagger so we don't overwhelm immediately // Small delay between launches to prevent DDOSing localhost
await new Promise(r => setTimeout(r, 100)); await new Promise(r => setTimeout(r, 50));
} }
try { await Promise.all(promises);
await Promise.all(promises);
console.log("✅ All simulated trips finished successfully."); const durationSec = ((Date.now() - startTime) / 1000).toFixed(2);
} catch (e) { const tps = (metrics.successful / durationSec).toFixed(2);
console.error("❌ Some trips failed.", e);
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(); runTest();