2024-11-26 17:04:22 -05:00
|
|
|
import { attemptLoginOrRegister, createRoomContainer, captureResourceUsageForContainers } from './utility/apiServices.js';
|
2024-11-15 17:46:01 -05:00
|
|
|
import { Student } from './class/student.js';
|
|
|
|
|
import { Teacher } from './class/teacher.js';
|
2024-11-26 17:04:22 -05:00
|
|
|
import { writeMetricsToFile, generateGraphs } from './utility/writeMetrics.js';
|
2024-11-15 17:46:01 -05:00
|
|
|
|
|
|
|
|
const BASE_URL = 'http://localhost';
|
2024-11-15 19:35:41 -05:00
|
|
|
const user = { username: 'admin@example.com', password: 'adminPassword' };
|
2024-11-26 17:04:22 -05:00
|
|
|
const numberRooms = 20;
|
|
|
|
|
const studentPerRoom = 58; // Max: 60, 1 reserved for teacher
|
2024-11-15 17:46:01 -05:00
|
|
|
const roomAssociations = {};
|
2024-11-26 17:04:22 -05:00
|
|
|
const allSockets = []; // Tracks all active WebSocket connections
|
2024-11-15 19:57:55 -05:00
|
|
|
|
|
|
|
|
const metrics = {
|
|
|
|
|
roomsCreated: 0,
|
|
|
|
|
roomsFailed: 0,
|
|
|
|
|
teachersConnected: 0,
|
|
|
|
|
teachersFailed: 0,
|
|
|
|
|
studentsConnected: 0,
|
|
|
|
|
studentsFailed: 0,
|
2024-11-26 17:04:22 -05:00
|
|
|
messagesSent: 0,
|
|
|
|
|
messagesReceived: 0,
|
|
|
|
|
totalLatency: 0,
|
|
|
|
|
maxLatency: 0,
|
|
|
|
|
minLatency: Number.MAX_SAFE_INTEGER,
|
|
|
|
|
throughput: 0,
|
2024-11-15 19:57:55 -05:00
|
|
|
startTime: null,
|
|
|
|
|
endTime: null,
|
|
|
|
|
};
|
2024-11-15 17:46:01 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Creates rooms and tracks their creation
|
2024-11-15 19:35:41 -05:00
|
|
|
async function createRoomContainers(token) {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.time('Room creation time');
|
2024-11-15 19:35:41 -05:00
|
|
|
const roomCreationPromises = Array.from({ length: numberRooms }, async () => {
|
2024-11-26 17:04:22 -05:00
|
|
|
try {
|
|
|
|
|
const room = await createRoomContainer(BASE_URL, token);
|
|
|
|
|
if (room?.id) {
|
|
|
|
|
roomAssociations[room.id] = { teacher: null, students: [] };
|
|
|
|
|
metrics.roomsCreated++;
|
|
|
|
|
console.log(`Room created with ID: ${room.id}`);
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.roomsFailed++;
|
2024-11-26 17:04:22 -05:00
|
|
|
console.warn('Failed to create a room.');
|
2024-11-15 19:35:41 -05:00
|
|
|
}
|
|
|
|
|
});
|
2024-11-15 17:46:01 -05:00
|
|
|
|
|
|
|
|
await Promise.allSettled(roomCreationPromises);
|
2024-11-26 17:04:22 -05:00
|
|
|
console.timeEnd('Room creation time');
|
|
|
|
|
console.log(`Total rooms created: ${Object.keys(roomAssociations).length}`);
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Connects teachers to their respective rooms
|
2024-11-15 19:35:41 -05:00
|
|
|
async function addAndConnectTeachers() {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.time('Teacher connection time');
|
|
|
|
|
const teacherPromises = Object.keys(roomAssociations).map(async (roomId, index) => {
|
2024-11-15 19:35:41 -05:00
|
|
|
const teacher = new Teacher(`teacher_${index}`, roomId);
|
2024-11-15 19:57:55 -05:00
|
|
|
const start = Date.now();
|
2024-11-15 19:35:41 -05:00
|
|
|
const socket = await teacher.connectToRoom(BASE_URL);
|
2024-11-15 19:57:55 -05:00
|
|
|
const latency = Date.now() - start;
|
2024-11-15 19:35:41 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
metrics.totalLatency += latency;
|
|
|
|
|
metrics.maxLatency = Math.max(metrics.maxLatency, latency);
|
|
|
|
|
metrics.minLatency = Math.min(metrics.minLatency, latency);
|
|
|
|
|
|
2024-11-15 19:35:41 -05:00
|
|
|
if (socket.connected) {
|
2024-11-15 19:57:55 -05:00
|
|
|
allSockets.push(socket);
|
2024-11-15 19:35:41 -05:00
|
|
|
roomAssociations[roomId].teacher = teacher;
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.teachersConnected++;
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log(`Teacher ${teacher.username} connected to room ${roomId}. Latency: ${latency}ms`);
|
2024-11-15 19:35:41 -05:00
|
|
|
} else {
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.teachersFailed++;
|
2024-11-26 17:04:22 -05:00
|
|
|
console.warn(`Failed to connect teacher ${index} to room ${roomId}`);
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
await Promise.allSettled(teacherPromises);
|
|
|
|
|
console.timeEnd('Teacher connection time');
|
|
|
|
|
console.log('All teachers connected to their respective rooms.');
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Connects students to their respective rooms
|
2024-11-15 17:46:01 -05:00
|
|
|
async function addAndConnectStudents() {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.time('Student connection time');
|
|
|
|
|
const studentPromises = Object.entries(roomAssociations).flatMap(([roomId, association], roomIndex) =>
|
2024-11-15 19:35:41 -05:00
|
|
|
Array.from({ length: studentPerRoom }, async (_, i) => {
|
2024-11-15 17:46:01 -05:00
|
|
|
const student = new Student(`student_${roomIndex}_${i}`, roomId);
|
2024-11-15 19:57:55 -05:00
|
|
|
const start = Date.now();
|
2024-11-15 19:35:41 -05:00
|
|
|
const socket = await student.connectToRoom(BASE_URL);
|
2024-11-15 19:57:55 -05:00
|
|
|
const latency = Date.now() - start;
|
2024-11-15 19:35:41 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
metrics.totalLatency += latency;
|
|
|
|
|
metrics.maxLatency = Math.max(metrics.maxLatency, latency);
|
|
|
|
|
metrics.minLatency = Math.min(metrics.minLatency, latency);
|
|
|
|
|
|
2024-11-15 19:35:41 -05:00
|
|
|
if (socket.connected) {
|
2024-11-15 19:57:55 -05:00
|
|
|
allSockets.push(socket);
|
2024-11-15 19:35:41 -05:00
|
|
|
association.students.push(student);
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.studentsConnected++;
|
2024-11-15 19:35:41 -05:00
|
|
|
} else {
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.studentsFailed++;
|
2024-11-26 17:04:22 -05:00
|
|
|
console.warn(`Failed to connect student ${roomIndex}_${i} to room ${roomId}`);
|
2024-11-15 19:35:41 -05:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
);
|
2024-11-15 17:46:01 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
await Promise.allSettled(studentPromises);
|
|
|
|
|
console.timeEnd('Student connection time');
|
|
|
|
|
console.log('All students connected to their respective rooms.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Simulates conversations in all rooms
|
|
|
|
|
async function simulateConversation() {
|
|
|
|
|
console.log("Conversation simulation started...");
|
|
|
|
|
const messages = [
|
|
|
|
|
"Bonjour, tout le monde !",
|
|
|
|
|
"Pouvez-vous répondre à la question 1 ?",
|
|
|
|
|
"J'ai une question sur l'exercice.",
|
|
|
|
|
"Voici la réponse à la question 1.",
|
|
|
|
|
"Merci pour vos réponses, continuons avec la question 2.",
|
|
|
|
|
"Je ne comprends pas bien, pouvez-vous expliquer à nouveau ?",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const interval = 1000;
|
|
|
|
|
const duration = 10000;
|
|
|
|
|
const startTime = Date.now();
|
|
|
|
|
|
|
|
|
|
while (Date.now() - startTime < duration) {
|
|
|
|
|
for (const [roomId, association] of Object.entries(roomAssociations)) {
|
|
|
|
|
if (association.teacher) {
|
|
|
|
|
const teacherMessage = `Teacher says: ${messages[Math.floor(Math.random() * messages.length)]}`;
|
|
|
|
|
association.teacher.sendMessage(teacherMessage);
|
|
|
|
|
metrics.messagesSent++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const student of association.students) {
|
|
|
|
|
const studentMessage = `${student.username} says: ${messages[Math.floor(Math.random() * messages.length)]}`;
|
|
|
|
|
student.sendMessage(studentMessage);
|
|
|
|
|
metrics.messagesSent++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log("Conversation simulation ended.");
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Closes all active WebSocket connections
|
2024-11-15 17:46:01 -05:00
|
|
|
function closeAllSockets() {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log('Closing all Socket.IO connections...');
|
2024-11-15 17:46:01 -05:00
|
|
|
allSockets.forEach((socket) => {
|
2024-11-15 19:57:55 -05:00
|
|
|
if (socket && socket.connected) {
|
2024-11-15 19:35:41 -05:00
|
|
|
try {
|
2024-11-15 19:57:55 -05:00
|
|
|
socket.disconnect();
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log('Socket.IO connection disconnected.');
|
2024-11-15 19:35:41 -05:00
|
|
|
} catch (error) {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.error('Error disconnecting Socket.IO connection:', error.message);
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log('All Socket.IO connections have been disconnected.');
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Main function to orchestrate the workflow
|
2024-11-15 17:46:01 -05:00
|
|
|
async function main() {
|
|
|
|
|
try {
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.startTime = new Date();
|
2024-11-26 17:04:22 -05:00
|
|
|
|
|
|
|
|
// Login or register
|
2024-11-15 17:46:01 -05:00
|
|
|
const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password);
|
2024-11-26 17:04:22 -05:00
|
|
|
if (!token) throw new Error('Failed to login or register.');
|
2024-11-15 17:46:01 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Room creation
|
2024-11-15 19:57:55 -05:00
|
|
|
await createRoomContainers(token);
|
2024-11-26 17:04:22 -05:00
|
|
|
|
|
|
|
|
// Resource monitoring and test activities
|
|
|
|
|
const roomIds = Object.keys(roomAssociations);
|
|
|
|
|
const usageCaptureInterval = 100;
|
|
|
|
|
let testCompleted = false;
|
|
|
|
|
|
|
|
|
|
const resourceCapturePromise = captureResourceUsageForContainers(
|
|
|
|
|
BASE_URL,
|
|
|
|
|
roomIds,
|
|
|
|
|
usageCaptureInterval,
|
|
|
|
|
() => testCompleted,
|
|
|
|
|
metrics
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const testPromise = (async () => {
|
|
|
|
|
await addAndConnectTeachers();
|
|
|
|
|
await addAndConnectStudents();
|
|
|
|
|
await simulateConversation();
|
|
|
|
|
testCompleted = true;
|
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
await Promise.all([resourceCapturePromise, testPromise]);
|
2024-11-15 17:46:01 -05:00
|
|
|
|
2024-11-15 19:57:55 -05:00
|
|
|
metrics.endTime = new Date();
|
2024-11-26 17:04:22 -05:00
|
|
|
writeMetricsToFile(metrics);
|
|
|
|
|
await generateGraphs(metrics.resourceUsage, metrics);
|
2024-11-15 20:09:56 -05:00
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log("All tasks completed successfully!");
|
2024-11-15 17:46:01 -05:00
|
|
|
} catch (error) {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.error('Error:', error.message);
|
2024-11-15 17:46:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
// Handle process interruptions
|
2024-11-15 17:46:01 -05:00
|
|
|
process.on('SIGINT', () => {
|
2024-11-26 17:04:22 -05:00
|
|
|
console.log('Process interrupted (Ctrl+C).');
|
2024-11-15 17:46:01 -05:00
|
|
|
closeAllSockets();
|
2024-11-15 19:35:41 -05:00
|
|
|
process.exit(0);
|
2024-11-15 17:46:01 -05:00
|
|
|
});
|
|
|
|
|
|
2024-11-26 17:04:22 -05:00
|
|
|
process.on('exit', () => closeAllSockets());
|
|
|
|
|
process.on('uncaughtException', (err) => {
|
|
|
|
|
console.error('Uncaught Exception:', err);
|
|
|
|
|
closeAllSockets();
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
|
|
|
console.error('Unhandled Rejection:', promise, 'reason:', reason);
|
|
|
|
|
closeAllSockets();
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|
2024-11-15 17:46:01 -05:00
|
|
|
|
|
|
|
|
main();
|