import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as plugins from './plugins.js'; import { createTestServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../helpers/smtp.client.js'; tap.test('CPERF-04: should optimize CPU utilization', async (tools) => { const testId = 'CPERF-04-cpu-utilization'; console.log(`\n${testId}: Testing CPU utilization optimization...`); let scenarioCount = 0; // Helper function to measure CPU usage (simplified) const measureCpuUsage = async (duration: number) => { const start = process.cpuUsage(); const startTime = Date.now(); await new Promise(resolve => setTimeout(resolve, duration)); const end = process.cpuUsage(start); const elapsed = Date.now() - startTime; return { user: end.user / 1000, // Convert to milliseconds system: end.system / 1000, total: (end.user + end.system) / 1000, elapsed, userPercent: (end.user / 1000) / elapsed * 100, systemPercent: (end.system / 1000) / elapsed * 100, totalPercent: ((end.user + end.system) / 1000) / elapsed * 100 }; }; // Scenario 1: CPU usage during connection establishment await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage during connection establishment`); const testServer = await createTestServer({ onConnection: async (socket) => { console.log(' [Server] Client connected'); socket.write('220 cpu.example.com ESMTP\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-cpu.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); } else if (command === '.') { socket.write('250 OK\r\n'); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); // Measure CPU during multiple connection establishments const connectionCount = 10; console.log(` Establishing ${connectionCount} connections...`); const startCpu = process.cpuUsage(); const startTime = Date.now(); const clients: any[] = []; for (let i = 0; i < connectionCount; i++) { const client = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); clients.push(client); // Verify connection try { await client.verify(); } catch (error) { // Connection verification might not be available } } const endCpu = process.cpuUsage(startCpu); const elapsed = Date.now() - startTime; const cpuUsage = { user: endCpu.user / 1000, system: endCpu.system / 1000, total: (endCpu.user + endCpu.system) / 1000, userPercent: (endCpu.user / 1000) / elapsed * 100, systemPercent: (endCpu.system / 1000) / elapsed * 100, totalPercent: ((endCpu.user + endCpu.system) / 1000) / elapsed * 100 }; console.log(` Connection establishment CPU usage:`); console.log(` Total time: ${elapsed}ms`); console.log(` User CPU: ${cpuUsage.user.toFixed(1)}ms (${cpuUsage.userPercent.toFixed(1)}%)`); console.log(` System CPU: ${cpuUsage.system.toFixed(1)}ms (${cpuUsage.systemPercent.toFixed(1)}%)`); console.log(` Total CPU: ${cpuUsage.total.toFixed(1)}ms (${cpuUsage.totalPercent.toFixed(1)}%)`); console.log(` CPU per connection: ${(cpuUsage.total / connectionCount).toFixed(1)}ms`); // Close all connections await Promise.all(clients.map(client => { if (client.close) { return client.close(); } return Promise.resolve(); })); // CPU usage should be reasonable expect(cpuUsage.totalPercent).toBeLessThan(50); // Less than 50% CPU usage expect(cpuUsage.total / connectionCount).toBeLessThan(50); // Less than 50ms CPU per connection await testServer.server.close(); })(); // Scenario 2: CPU usage during message composition await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage during message composition`); const testServer = await createTestServer({ onConnection: async (socket) => { socket.write('220 composition.example.com ESMTP\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-composition.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); } else if (command === '.') { socket.write('250 OK\r\n'); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test different message compositions const compositionTests = [ { name: 'Simple text', email: new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Simple text message', text: 'This is a simple text message.' }) }, { name: 'HTML with formatting', email: new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'HTML message', html: '
This is an HTML message with formatting.
' }) }, { name: 'Multipart with text and HTML', email: new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Multipart message', text: 'Plain text version', html: 'HTML version
' }) }, { name: 'Message with small attachment', email: new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Message with attachment', text: 'Message with small attachment', attachments: [{ filename: 'test.txt', content: 'This is a test attachment with some content.' }] }) } ]; for (const test of compositionTests) { console.log(` Testing ${test.name}...`); const startCpu = process.cpuUsage(); const startTime = Date.now(); await smtpClient.sendMail(test.email); const endCpu = process.cpuUsage(startCpu); const elapsed = Date.now() - startTime; const cpuUsage = { user: endCpu.user / 1000, system: endCpu.system / 1000, total: (endCpu.user + endCpu.system) / 1000, totalPercent: ((endCpu.user + endCpu.system) / 1000) / elapsed * 100 }; console.log(` ${test.name}: ${cpuUsage.total.toFixed(1)}ms CPU (${cpuUsage.totalPercent.toFixed(1)}%)`); // CPU usage should be efficient for message composition expect(cpuUsage.totalPercent).toBeLessThan(25); // Less than 25% CPU expect(cpuUsage.total).toBeLessThan(100); // Less than 100ms CPU time } await testServer.server.close(); })(); // Scenario 3: CPU usage with concurrent operations await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage with concurrent operations`); const testServer = await createTestServer({ onConnection: async (socket) => { socket.write('220 concurrent.example.com ESMTP\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-concurrent.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); } else if (command === '.') { socket.write('250 OK\r\n'); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test sequential vs concurrent CPU usage const messageCount = 20; const emails = Array(messageCount).fill(null).map((_, i) => new plugins.smartmail.Email({ from: 'sender@example.com', to: [`recipient${i + 1}@example.com`], subject: `CPU test message ${i + 1}`, text: `Testing CPU utilization - message ${i + 1}` }) ); // Sequential sending console.log(` Sequential sending of ${messageCount} messages...`); const sequentialStartCpu = process.cpuUsage(); const sequentialStartTime = Date.now(); for (const email of emails) { await smtpClient.sendMail(email); } const sequentialEndCpu = process.cpuUsage(sequentialStartCpu); const sequentialElapsed = Date.now() - sequentialStartTime; const sequentialCpu = { total: (sequentialEndCpu.user + sequentialEndCpu.system) / 1000, totalPercent: ((sequentialEndCpu.user + sequentialEndCpu.system) / 1000) / sequentialElapsed * 100 }; console.log(` Sequential: ${sequentialCpu.total.toFixed(1)}ms CPU (${sequentialCpu.totalPercent.toFixed(1)}%)`); console.log(` Per message: ${(sequentialCpu.total / messageCount).toFixed(1)}ms CPU`); // Concurrent sending (new emails) const concurrentEmails = Array(messageCount).fill(null).map((_, i) => new plugins.smartmail.Email({ from: 'sender@example.com', to: [`concurrent${i + 1}@example.com`], subject: `Concurrent CPU test ${i + 1}`, text: `Testing concurrent CPU utilization - message ${i + 1}` }) ); console.log(` Concurrent sending of ${messageCount} messages...`); const concurrentStartCpu = process.cpuUsage(); const concurrentStartTime = Date.now(); await Promise.all(concurrentEmails.map(email => smtpClient.sendMail(email))); const concurrentEndCpu = process.cpuUsage(concurrentStartCpu); const concurrentElapsed = Date.now() - concurrentStartTime; const concurrentCpu = { total: (concurrentEndCpu.user + concurrentEndCpu.system) / 1000, totalPercent: ((concurrentEndCpu.user + concurrentEndCpu.system) / 1000) / concurrentElapsed * 100 }; console.log(` Concurrent: ${concurrentCpu.total.toFixed(1)}ms CPU (${concurrentCpu.totalPercent.toFixed(1)}%)`); console.log(` Per message: ${(concurrentCpu.total / messageCount).toFixed(1)}ms CPU`); // Compare efficiency const efficiency = sequentialCpu.total / concurrentCpu.total; console.log(` CPU efficiency ratio: ${efficiency.toFixed(2)}x`); // Concurrent should be more CPU efficient (higher throughput) expect(concurrentElapsed).toBeLessThan(sequentialElapsed); expect(concurrentCpu.totalPercent).toBeLessThan(80); // Less than 80% CPU await testServer.server.close(); })(); // Scenario 4: CPU usage with large attachments await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage with large attachments`); const testServer = await createTestServer({ onConnection: async (socket) => { socket.write('220 attachments.example.com ESMTP\r\n'); let inData = false; let dataSize = 0; socket.on('data', (data) => { if (inData) { dataSize += data.length; if (data.toString().includes('\r\n.\r\n')) { inData = false; console.log(` [Server] Received ${(dataSize / 1024).toFixed(1)}KB`); socket.write('250 OK\r\n'); dataSize = 0; } return; } const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-attachments.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); inData = true; } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); // Test different attachment sizes const attachmentSizes = [ { name: '10KB', size: 10 * 1024 }, { name: '100KB', size: 100 * 1024 }, { name: '1MB', size: 1024 * 1024 } ]; for (const attachSize of attachmentSizes) { console.log(` Testing ${attachSize.name} attachment...`); // Create binary attachment const attachmentData = Buffer.alloc(attachSize.size); for (let i = 0; i < attachmentData.length; i++) { attachmentData[i] = i % 256; } const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: `CPU test with ${attachSize.name} attachment`, text: `Testing CPU usage with ${attachSize.name} attachment`, attachments: [{ filename: `${attachSize.name}-file.bin`, content: attachmentData }] }); const startCpu = process.cpuUsage(); const startTime = Date.now(); await smtpClient.sendMail(email); const endCpu = process.cpuUsage(startCpu); const elapsed = Date.now() - startTime; const cpuUsage = { total: (endCpu.user + endCpu.system) / 1000, totalPercent: ((endCpu.user + endCpu.system) / 1000) / elapsed * 100 }; const cpuPerKB = cpuUsage.total / (attachSize.size / 1024); console.log(` ${attachSize.name}: ${cpuUsage.total.toFixed(1)}ms CPU (${cpuUsage.totalPercent.toFixed(1)}%)`); console.log(` CPU per KB: ${cpuPerKB.toFixed(3)}ms/KB`); // CPU usage should scale reasonably with attachment size expect(cpuUsage.totalPercent).toBeLessThan(50); expect(cpuPerKB).toBeLessThan(1); // Less than 1ms CPU per KB } await testServer.server.close(); })(); // Scenario 5: CPU usage with connection pooling await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage with connection pooling`); let connectionCount = 0; const testServer = await createTestServer({ onConnection: async (socket) => { connectionCount++; socket.write('220 pool.example.com ESMTP\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-pool.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); } else if (command === '.') { socket.write('250 OK\r\n'); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); // Compare individual connections vs pooled const messageCount = 15; // Individual connections console.log(` Testing ${messageCount} individual connections...`); connectionCount = 0; const individualStartCpu = process.cpuUsage(); const individualStartTime = Date.now(); for (let i = 0; i < messageCount; i++) { const client = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false }); const email = new plugins.smartmail.Email({ from: 'sender@example.com', to: [`individual${i + 1}@example.com`], subject: `Individual connection test ${i + 1}`, text: `Testing individual connection - message ${i + 1}` }); await client.sendMail(email); if (client.close) { await client.close(); } } const individualEndCpu = process.cpuUsage(individualStartCpu); const individualElapsed = Date.now() - individualStartTime; const individualConnections = connectionCount; const individualCpu = { total: (individualEndCpu.user + individualEndCpu.system) / 1000, totalPercent: ((individualEndCpu.user + individualEndCpu.system) / 1000) / individualElapsed * 100 }; console.log(` Individual: ${individualCpu.total.toFixed(1)}ms CPU, ${individualConnections} connections`); // Pooled connections console.log(` Testing pooled connections...`); connectionCount = 0; const pooledStartCpu = process.cpuUsage(); const pooledStartTime = Date.now(); const pooledClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 3, maxMessages: 100 }); const pooledEmails = Array(messageCount).fill(null).map((_, i) => new plugins.smartmail.Email({ from: 'sender@example.com', to: [`pooled${i + 1}@example.com`], subject: `Pooled connection test ${i + 1}`, text: `Testing pooled connection - message ${i + 1}` }) ); await Promise.all(pooledEmails.map(email => pooledClient.sendMail(email))); await pooledClient.close(); const pooledEndCpu = process.cpuUsage(pooledStartCpu); const pooledElapsed = Date.now() - pooledStartTime; const pooledConnections = connectionCount; const pooledCpu = { total: (pooledEndCpu.user + pooledEndCpu.system) / 1000, totalPercent: ((pooledEndCpu.user + pooledEndCpu.system) / 1000) / pooledElapsed * 100 }; console.log(` Pooled: ${pooledCpu.total.toFixed(1)}ms CPU, ${pooledConnections} connections`); const cpuEfficiency = individualCpu.total / pooledCpu.total; const connectionEfficiency = individualConnections / pooledConnections; console.log(` CPU efficiency: ${cpuEfficiency.toFixed(2)}x`); console.log(` Connection efficiency: ${connectionEfficiency.toFixed(2)}x`); // Pooling should be more CPU efficient expect(pooledCpu.total).toBeLessThan(individualCpu.total); expect(pooledConnections).toBeLessThan(individualConnections); expect(cpuEfficiency).toBeGreaterThan(1.2); // At least 20% more efficient await testServer.server.close(); })(); // Scenario 6: CPU usage under stress await (async () => { scenarioCount++; console.log(`\nScenario ${scenarioCount}: Testing CPU usage under stress`); let messageCount = 0; const testServer = await createTestServer({ onConnection: async (socket) => { socket.write('220 stress.example.com ESMTP\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); if (command.startsWith('EHLO')) { socket.write('250-stress.example.com\r\n'); socket.write('250 OK\r\n'); } else if (command.startsWith('MAIL FROM:')) { socket.write('250 OK\r\n'); } else if (command.startsWith('RCPT TO:')) { socket.write('250 OK\r\n'); } else if (command === 'DATA') { socket.write('354 Start mail input\r\n'); } else if (command === '.') { messageCount++; socket.write(`250 OK: Message ${messageCount}\r\n`); } else if (command === 'QUIT') { socket.write('221 Bye\r\n'); socket.end(); } }); } }); const pooledClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, pool: true, maxConnections: 5, maxMessages: 100 }); // Stress test with many messages const stressMessageCount = 50; const stressEmails = Array(stressMessageCount).fill(null).map((_, i) => new plugins.smartmail.Email({ from: 'sender@example.com', to: [`stress${i + 1}@example.com`], subject: `Stress test message ${i + 1}`, text: `Testing CPU under stress - message ${i + 1}` }) ); console.log(` Stress testing with ${stressMessageCount} concurrent messages...`); const stressStartCpu = process.cpuUsage(); const stressStartTime = Date.now(); // Monitor CPU usage during stress test const cpuSamples: number[] = []; const sampleInterval = setInterval(() => { const currentCpu = process.cpuUsage(stressStartCpu); const currentElapsed = Date.now() - stressStartTime; const currentPercent = ((currentCpu.user + currentCpu.system) / 1000) / currentElapsed * 100; cpuSamples.push(currentPercent); }, 100); await Promise.all(stressEmails.map(email => pooledClient.sendMail(email))); clearInterval(sampleInterval); const stressEndCpu = process.cpuUsage(stressStartCpu); const stressElapsed = Date.now() - stressStartTime; const stressCpu = { total: (stressEndCpu.user + stressEndCpu.system) / 1000, totalPercent: ((stressEndCpu.user + stressEndCpu.system) / 1000) / stressElapsed * 100 }; const maxCpuSample = Math.max(...cpuSamples); const avgCpuSample = cpuSamples.reduce((a, b) => a + b, 0) / cpuSamples.length; console.log(` Stress test results:`); console.log(` Total CPU: ${stressCpu.total.toFixed(1)}ms (${stressCpu.totalPercent.toFixed(1)}%)`); console.log(` Peak CPU: ${maxCpuSample.toFixed(1)}%`); console.log(` Average CPU: ${avgCpuSample.toFixed(1)}%`); console.log(` Messages per CPU ms: ${(stressMessageCount / stressCpu.total).toFixed(2)}`); console.log(` Throughput: ${(stressMessageCount / stressElapsed * 1000).toFixed(1)} msg/sec`); await pooledClient.close(); // CPU usage should remain reasonable under stress expect(stressCpu.totalPercent).toBeLessThan(90); // Less than 90% CPU expect(maxCpuSample).toBeLessThan(100); // No sustained 100% CPU expect(stressMessageCount / stressCpu.total).toBeGreaterThan(0.1); // At least 0.1 msg/ms efficiency await testServer.server.close(); })(); console.log(`\n${testId}: All ${scenarioCount} CPU utilization scenarios tested ✓`); });