Update: 2026-07-17 00:13:30
This commit is contained in:
@@ -68,10 +68,7 @@
|
|||||||
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
|
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||||
android:value="@string/default_notification_channel_id" />
|
android:value="@string/default_notification_channel_id" />
|
||||||
<meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="false" />
|
<meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="false" />
|
||||||
<!-- Android Auto Metadata -->
|
|
||||||
<meta-data
|
|
||||||
android:name="com.android.car.meta"
|
|
||||||
android:resource="@xml/automotive_app_desc" />
|
|
||||||
<!-- Main Activity -->
|
<!-- Main Activity -->
|
||||||
<activity android:name=".MainActivity"
|
<activity android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
@@ -138,14 +135,7 @@
|
|||||||
<service android:name=".MyFirebaseMessagingService" android:exported="false" />
|
<service android:name=".MyFirebaseMessagingService" android:exported="false" />
|
||||||
<service android:name=".LocationUpdatesService" android:exported="false"
|
<service android:name=".LocationUpdatesService" android:exported="false"
|
||||||
android:foregroundServiceType="location" />
|
android:foregroundServiceType="location" />
|
||||||
<!-- Android Auto Car App Service -->
|
|
||||||
<service
|
|
||||||
android:name=".MyCarAppService"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="androidx.car.app.CarAppService" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
<!-- خدمة Firebase الرسمية لاستقبال رسائل FCM -->
|
<!-- خدمة Firebase الرسمية لاستقبال رسائل FCM -->
|
||||||
<service android:name="com.google.firebase.messaging.FirebaseMessagingService"
|
<service android:name="com.google.firebase.messaging.FirebaseMessagingService"
|
||||||
android:exported="false" tools:replace="android:exported">
|
android:exported="false" tools:replace="android:exported">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: siro_driver
|
|||||||
description: "A new Flutter project."
|
description: "A new Flutter project."
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 1.0.0+4
|
version: 1.0.0+5
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.5 <4.0.0"
|
sdk: ">=3.0.5 <4.0.0"
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
// stress_test/generate_mock_data.php
|
||||||
|
// Generates a valid JWT for the driver using the system's JWT_SECRET_KEY
|
||||||
|
require_once dirname(__DIR__) . '/backend/connect.php';
|
||||||
|
require_once dirname(__DIR__) . '/loction_server/vendor/autoload.php';
|
||||||
|
|
||||||
|
use Firebase\JWT\JWT;
|
||||||
|
use Firebase\JWT\Key;
|
||||||
|
|
||||||
|
function getJwtSecret(): string {
|
||||||
|
$keyPath = getenv('JWT_SECRET_KEY_PATH');
|
||||||
|
if ($keyPath && file_exists($keyPath)) {
|
||||||
|
return trim(file_get_contents($keyPath));
|
||||||
|
}
|
||||||
|
return getenv('JWT_SECRET_KEY') ?: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$secret = getJwtSecret();
|
||||||
|
if (empty($secret)) {
|
||||||
|
die("Error: JWT_SECRET_KEY not found. Cannot generate mock JWT.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$driverId = $argv[1] ?? '999999';
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'sub' => (string)$driverId,
|
||||||
|
'role' => 'driver',
|
||||||
|
'iat' => time(),
|
||||||
|
'exp' => time() + 86400
|
||||||
|
];
|
||||||
|
|
||||||
|
$jwt = JWT::encode($payload, $secret, 'HS256');
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'driver_id' => $driverId,
|
||||||
|
'jwt' => $jwt
|
||||||
|
]);
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
const { io } = require('socket.io-client');
|
||||||
|
const axios = require('axios');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const yargs = require('yargs/yargs');
|
||||||
|
const { hideBin } = require('yargs/helpers');
|
||||||
|
|
||||||
|
const argv = yargs(hideBin(process.argv))
|
||||||
|
.option('trips', {
|
||||||
|
alias: 't',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Number of concurrent trips to simulate',
|
||||||
|
default: 1
|
||||||
|
})
|
||||||
|
.option('base-url', {
|
||||||
|
alias: 'b',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Base URL for backend APIs',
|
||||||
|
default: 'http://localhost/backend'
|
||||||
|
})
|
||||||
|
.option('socket-url', {
|
||||||
|
alias: 's',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Location server socket URL',
|
||||||
|
default: 'ws://localhost:2020'
|
||||||
|
})
|
||||||
|
.argv;
|
||||||
|
|
||||||
|
// Helper to get JWT for mock driver
|
||||||
|
function getMockDriverJwt(driverId) {
|
||||||
|
try {
|
||||||
|
const output = execSync(`php generate_mock_data.php ${driverId}`).toString();
|
||||||
|
return JSON.parse(output).jwt;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to generate JWT for driver ${driverId}`, err.message);
|
||||||
|
return 'mock_jwt';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
|
||||||
|
// 1. Connect Driver to Socket
|
||||||
|
const socket = io(argv.socketUrl, {
|
||||||
|
query: {
|
||||||
|
driver_id: driverId,
|
||||||
|
platform: 'android',
|
||||||
|
jwt: driverJwt
|
||||||
|
},
|
||||||
|
transports: ['websocket']
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let rideId = null;
|
||||||
|
|
||||||
|
socket.on('connect', async () => {
|
||||||
|
console.log(`[Trip ${tripIndex}] Driver ${driverId} connected to socket.`);
|
||||||
|
|
||||||
|
// 2. Passenger Requests Ride
|
||||||
|
try {
|
||||||
|
const addRideFormData = new URLSearchParams({
|
||||||
|
passenger_id: passengerId,
|
||||||
|
start_location: '31.95,35.91', // Amman
|
||||||
|
end_location: '31.96,35.92',
|
||||||
|
price: '5',
|
||||||
|
price_token: 'dummy',
|
||||||
|
distance: '2',
|
||||||
|
carType: 'Economy',
|
||||||
|
passenger_name: 'Test Passenger',
|
||||||
|
passenger_phone: '0790000000',
|
||||||
|
start_name: 'Start',
|
||||||
|
end_name: 'End'
|
||||||
|
});
|
||||||
|
|
||||||
|
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' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[Trip ${tripIndex}] Error requesting ride:`, err.message);
|
||||||
|
socket.disconnect();
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('market_new_ride', async (payload) => {
|
||||||
|
rideId = payload.id;
|
||||||
|
console.log(`[Trip ${tripIndex}] Driver ${driverId} received ride offer #${rideId}. Accepting...`);
|
||||||
|
|
||||||
|
// 3. Driver Accepts Ride
|
||||||
|
try {
|
||||||
|
const acceptFormData = new URLSearchParams({
|
||||||
|
id: rideId,
|
||||||
|
driver_id: driverId,
|
||||||
|
status: 'accepted'
|
||||||
|
});
|
||||||
|
|
||||||
|
const acceptStart = Date.now();
|
||||||
|
await axios.post(`${argv.baseUrl}/ride/rides/acceptRide.php`, acceptFormData.toString(), {
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||||
|
});
|
||||||
|
console.log(`[Trip ${tripIndex}] Driver ${driverId} accepted ride #${rideId}. Response time: ${Date.now() - acceptStart}ms`);
|
||||||
|
|
||||||
|
// 4. Simulate Driving (Updates Location)
|
||||||
|
let steps = 0;
|
||||||
|
const driveInterval = setInterval(async () => {
|
||||||
|
steps++;
|
||||||
|
socket.emit('update_location', {
|
||||||
|
lat: 31.95 + (steps * 0.001),
|
||||||
|
lng: 35.91 + (steps * 0.001),
|
||||||
|
heading: 90,
|
||||||
|
speed: 40,
|
||||||
|
status: 'on'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (steps === 3) {
|
||||||
|
// Driver Arrived / Starts Ride
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (steps === 6) {
|
||||||
|
clearInterval(driveInterval);
|
||||||
|
// 5. Finish Ride
|
||||||
|
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}.`);
|
||||||
|
|
||||||
|
socket.disconnect();
|
||||||
|
resolve(`Trip ${tripIndex} completed successfully.`);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[Trip ${tripIndex}] Error during ride execution:`, err.message);
|
||||||
|
socket.disconnect();
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('disconnect', () => {
|
||||||
|
console.log(`[Trip ${tripIndex}] Driver ${driverId} disconnected.`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runTest() {
|
||||||
|
console.log(`🚀 Starting Load Test with ${argv.trips} concurrent trips`);
|
||||||
|
const promises = [];
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(promises);
|
||||||
|
console.log("✅ All simulated trips finished successfully.");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("❌ Some trips failed.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runTest();
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "siro-stress-test",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Stress testing suite for Siro ride-hailing services",
|
||||||
|
"main": "load_test.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node load_test.js",
|
||||||
|
"test:multi": "node load_test.js --trips=100"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"socket.io-client": "^4.7.5",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
|
"yargs": "^17.7.2",
|
||||||
|
"dotenv": "^16.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user