import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js'; import { Email } from '../../../ts/mail/core/classes.email.js'; import * as net from 'net'; let testServer: ITestServer; tap.test('setup test SMTP server', async () => { testServer = await startTestServer({ port: 2601, tlsEnabled: false, authRequired: false }); expect(testServer).toBeTruthy(); expect(testServer.port).toEqual(2601); }); tap.test('CREL-02: Handle network interruption during verification', async () => { // Create a server that drops connections mid-session const interruptServer = net.createServer((socket) => { socket.write('220 Interrupt Test Server\r\n'); socket.on('data', (data) => { const command = data.toString().trim(); console.log(`Server received: ${command}`); if (command.startsWith('EHLO')) { // Start sending multi-line response then drop socket.write('250-test.server\r\n'); socket.write('250-PIPELINING\r\n'); // Simulate network interruption setTimeout(() => { console.log('Simulating network interruption...'); socket.destroy(); }, 100); } }); }); await new Promise((resolve) => { interruptServer.listen(2602, () => resolve()); }); const smtpClient = createSmtpClient({ host: '127.0.0.1', port: 2602, secure: false, connectionTimeout: 2000, debug: true }); // Should handle the interruption gracefully const result = await smtpClient.verify(); expect(result).toBeFalse(); console.log('✅ Handled network interruption during verification'); await new Promise((resolve) => { interruptServer.close(() => resolve()); }); }); tap.test('CREL-02: Recovery after brief network glitch', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); // Send email successfully const email1 = new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Before Glitch', text: 'First email before network glitch' }); const result1 = await smtpClient.sendMail(email1); expect(result1.success).toBeTrue(); console.log('First email sent successfully'); // Close to simulate brief network issue await smtpClient.close(); console.log('Simulating brief network glitch...'); // Wait a moment await new Promise(resolve => setTimeout(resolve, 500)); // Try to send another email - should reconnect automatically const email2 = new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'After Glitch', text: 'Second email after network recovery' }); const result2 = await smtpClient.sendMail(email2); expect(result2.success).toBeTrue(); console.log('✅ Recovered from network glitch successfully'); await smtpClient.close(); }); tap.test('CREL-02: Handle server becoming unresponsive', async () => { // Create a server that stops responding const unresponsiveServer = net.createServer((socket) => { socket.write('220 Unresponsive Server\r\n'); let commandCount = 0; socket.on('data', (data) => { const command = data.toString().trim(); commandCount++; console.log(`Command ${commandCount}: ${command}`); // Stop responding after first command if (commandCount === 1 && command.startsWith('EHLO')) { console.log('Server becoming unresponsive...'); // Don't send any response - simulate hung server } }); // Don't close the socket, just stop responding }); await new Promise((resolve) => { unresponsiveServer.listen(2604, () => resolve()); }); const smtpClient = createSmtpClient({ host: '127.0.0.1', port: 2604, secure: false, connectionTimeout: 2000, // Short timeout to detect unresponsiveness debug: true }); // Should timeout when server doesn't respond const result = await smtpClient.verify(); expect(result).toBeFalse(); console.log('✅ Detected unresponsive server'); await new Promise((resolve) => { unresponsiveServer.close(() => resolve()); }); }); tap.test('CREL-02: Handle large email successfully', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 10000, socketTimeout: 10000, debug: true }); // Create a large email const largeText = 'x'.repeat(10000); // 10KB of text const email = new Email({ from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Large Email Test', text: largeText }); // Should complete successfully despite size const result = await smtpClient.sendMail(email); expect(result.success).toBeTrue(); console.log('✅ Large email sent successfully'); await smtpClient.close(); }); tap.test('CREL-02: Rapid reconnection after interruption', async () => { const smtpClient = createSmtpClient({ host: testServer.hostname, port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); // Rapid cycle of verify, close, verify for (let i = 0; i < 3; i++) { const result = await smtpClient.verify(); expect(result).toBeTrue(); await smtpClient.close(); console.log(`Rapid cycle ${i + 1} completed`); // Very short delay await new Promise(resolve => setTimeout(resolve, 50)); } console.log('✅ Rapid reconnection handled successfully'); }); tap.test('cleanup test SMTP server', async () => { if (testServer) { await stopTestServer(testServer); } }); export default tap.start();