From 1a7be0ad7943ed5783fcf53b48259398bceb5d87 Mon Sep 17 00:00:00 2001 From: MathieuSevignyLavallee <89943988+MathieuSevignyLavallee@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:31:48 -0500 Subject: [PATCH] ajout de metrique de sommaire --- test/stressTest/main.js | 53 +++++++++++++++----- test/stressTest/utility/metrics_generator.js | 52 ++++++++++++++++++- test/stressTest/utility/test_metrics.js | 46 +++++++++++++++++ 3 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 test/stressTest/utility/test_metrics.js diff --git a/test/stressTest/main.js b/test/stressTest/main.js index b6d9c54..6027f4f 100644 --- a/test/stressTest/main.js +++ b/test/stressTest/main.js @@ -2,6 +2,7 @@ import { attemptLoginOrRegister, createRoomContainer } from './utility/apiServic import { Student } from './class/student.js'; import { Teacher } from './class/teacher.js'; import { Watcher } from './class/watcher.js'; +import { TestMetrics } from './utility/test_metrics.js'; import dotenv from 'dotenv'; import generateMetricsReport from './utility/metrics_generator.js'; @@ -27,19 +28,32 @@ const config = { }; const rooms = new Map(); +const metrics = new TestMetrics(); async function setupRoom(token, index) { try { const room = await createRoomContainer(config.baseUrl, token); if (!room?.id) throw new Error('Room creation failed'); + metrics.roomsCreated++; const teacher = new Teacher(`teacher_${index}`, room.id); const watcher = new Watcher(`watcher_${index}`, room.id); + await Promise.all([ teacher.connectToRoom(config.baseUrl) - .catch(err => console.warn(`Teacher ${index} connection failed:`, err.message)), + .then(() => metrics.usersConnected++) + .catch(err => { + metrics.userConnectionsFailed++; + metrics.logError('teacherConnection', err); + console.warn(`Teacher ${index} connection failed:`, err.message); + }), watcher.connectToRoom(config.baseUrl) - .catch(err => console.warn(`Watcher ${index} connection failed:`, err.message)) + .then(() => metrics.usersConnected++) + .catch(err => { + metrics.userConnectionsFailed++; + metrics.logError('watcherConnection', err); + console.warn(`Watcher ${index} connection failed:`, err.message); + }) ]); const students = Array.from({ length: config.rooms.usersPerRoom - 2 }, @@ -48,6 +62,8 @@ async function setupRoom(token, index) { rooms.set(room.id, { teacher, watcher, students }); return room.id; } catch (err) { + metrics.roomsFailed++; + metrics.logError('roomSetup', err); console.warn(`Room ${index} setup failed:`, err.message); return null; } @@ -61,9 +77,15 @@ async function connectParticipants(roomId) { const batch = participants.slice(i, i + config.rooms.batchSize); await Promise.all(batch.map(p => Promise.race([ - p.connectToRoom(config.baseUrl), + p.connectToRoom(config.baseUrl).then(() => { + metrics.usersConnected++; + }), new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 10000)) - ]).catch(err => console.warn(`Connection failed for ${p.username}:`, err.message)) + ]).catch(err => { + metrics.userConnectionsFailed++; + metrics.logError('studentConnection', err); + console.warn(`Connection failed for ${p.username}:`, err.message); + }) )); await new Promise(resolve => setTimeout(resolve, config.rooms.batchDelay)); } @@ -75,23 +97,30 @@ async function simulate() { const expectedResponses = connectedStudents.length; for (let i = 0; i < config.simulation.maxMessages; i++) { + metrics.messagesAttempted++; const initialMessages = teacher.nbrMessageReceived; - teacher.broadcastMessage(`Message ${i + 1} from ${teacher.username}`); - try { + teacher.broadcastMessage(`Message ${i + 1} from ${teacher.username}`); + metrics.messagesSent++; + await Promise.race([ new Promise(resolve => { const checkResponses = setInterval(() => { const receivedResponses = teacher.nbrMessageReceived - initialMessages; if (receivedResponses >= expectedResponses) { + metrics.messagesReceived += receivedResponses; clearInterval(checkResponses); resolve(); } }, 100); - }) + }), + new Promise((_, reject) => + setTimeout(() => reject(new Error('Response timeout')), config.simulation.responseTimeout) + ) ]); } catch (error) { + metrics.logError('messaging', error); console.error(`Error in room ${roomId} message ${i + 1}:`, error); } @@ -99,7 +128,6 @@ async function simulate() { } }); - // Wait for all simulations to complete await Promise.all(simulations); console.log('All room simulations completed'); } @@ -111,7 +139,7 @@ async function generateReport() { watcher.roomRessourcesData ]) ); - return generateMetricsReport(data); + return generateMetricsReport(data,metrics); } function cleanup() { @@ -134,20 +162,21 @@ async function main() { await Promise.all(roomIds.filter(Boolean).map(connectParticipants)); console.log('Retrieving baseline metrics...'); - await new Promise(resolve => setTimeout(resolve, 10000)); // Baseline metrics + await new Promise(resolve => setTimeout(resolve, 10000)); console.log('Starting simulation across all rooms...'); await simulate(); console.log('Simulation complete. Waiting for system stabilization...'); - await new Promise(resolve => setTimeout(resolve, 10000)); // System stabilization + await new Promise(resolve => setTimeout(resolve, 10000)); - console.log('All simulations finished, generating final report...'); + console.log('Generating final report...'); const folderName = await generateReport(); console.log(`Metrics report generated in ${folderName.outputDir}`); console.log('All done!'); } catch (error) { + metrics.logError('main', error); console.error('Error:', error.message); } finally { cleanup(); diff --git a/test/stressTest/utility/metrics_generator.js b/test/stressTest/utility/metrics_generator.js index 45c21a8..e7d903a 100644 --- a/test/stressTest/utility/metrics_generator.js +++ b/test/stressTest/utility/metrics_generator.js @@ -122,10 +122,60 @@ async function generateGlobalGraphs(data, chartJSNodeCanvas, globalMetricsDir) { ]); } -export default async function generateMetricsReport(allRoomsData) { +async function saveMetricsSummary(metrics, baseOutputDir) { + const metricsData = metrics.getSummary(); + + // Save as JSON + fs.writeFileSync( + path.join(baseOutputDir, 'metrics-summary.json'), + JSON.stringify(metricsData, null, 2) + ); + + // Save as formatted text + const textSummary = ` +Load Test Summary +================ + +Rooms +----- +Created: ${metricsData.rooms.created} +Failed: ${metricsData.rooms.failed} +Total: ${metricsData.rooms.total} + +Users +----- +Connected: ${metricsData.users.connected} +Failed: ${metricsData.users.failed} +Total: ${metricsData.users.total} + +Messages +-------- +Attempted: ${metricsData.messages.attempted} +Sent: ${metricsData.messages.sent} +Received: ${metricsData.messages.received} + +Errors by Category +---------------- +${Object.entries(metricsData.errors) + .map(([category, count]) => `${category}: ${count}`) + .join('\n')} +`; + + fs.writeFileSync( + path.join(baseOutputDir, 'metrics-summary.txt'), + textSummary.trim() + ); +} + +export default async function generateMetricsReport(allRoomsData, testMetrics) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const baseOutputDir = `./output/${timestamp}`; ensureDirectoryExists(baseOutputDir); + + if (testMetrics) { + await saveMetricsSummary(testMetrics, baseOutputDir); + } + const globalMetricsDir = path.join(baseOutputDir, 'global'); ensureDirectoryExists(globalMetricsDir); diff --git a/test/stressTest/utility/test_metrics.js b/test/stressTest/utility/test_metrics.js new file mode 100644 index 0000000..a28bff0 --- /dev/null +++ b/test/stressTest/utility/test_metrics.js @@ -0,0 +1,46 @@ +export class TestMetrics { + constructor() { + this.reset(); + } + + reset() { + this.roomsCreated = 0; + this.roomsFailed = 0; + this.usersConnected = 0; + this.userConnectionsFailed = 0; + this.messagesAttempted = 0; + this.messagesSent = 0; + this.messagesReceived = 0; + this.errors = new Map(); + } + + logError(category, error) { + if (!this.errors.has(category)) { + this.errors.set(category, []); + } + this.errors.get(category).push(error); + } + + getSummary() { + return { + rooms: { + created: this.roomsCreated, + failed: this.roomsFailed, + total: this.roomsCreated + this.roomsFailed + }, + users: { + connected: this.usersConnected, + failed: this.userConnectionsFailed, + total: this.usersConnected + this.userConnectionsFailed + }, + messages: { + attempted: this.messagesAttempted, + sent: this.messagesSent, + received: this.messagesReceived + }, + errors: Object.fromEntries( + Array.from(this.errors.entries()).map(([k, v]) => [k, v.length]) + ) + }; + } +} \ No newline at end of file