dcrouter/test/suite/smtpclient_reliability/test.crel-02.network-interruption.ts

207 lines
5.8 KiB
TypeScript
Raw Permalink Normal View History

2025-05-24 16:19:19 +00:00
import { tap, expect } from '@git.zone/tstest/tapbundle';
2025-05-26 12:23:19 +00:00
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js';
2025-05-24 16:19:19 +00:00
import { Email } from '../../../ts/mail/core/classes.email.js';
import * as net from 'net';
2025-05-26 12:23:19 +00:00
let testServer: ITestServer;
2025-05-24 16:19:19 +00:00
tap.test('setup test SMTP server', async () => {
2025-05-26 12:23:19 +00:00
testServer = await startTestServer({
port: 2601,
tlsEnabled: false,
authRequired: false
});
2025-05-24 16:19:19 +00:00
expect(testServer).toBeTruthy();
2025-05-26 12:23:19 +00:00
expect(testServer.port).toEqual(2601);
2025-05-24 16:19:19 +00:00
});
2025-05-26 12:23:19 +00:00
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');
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
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);
}
});
2025-05-24 16:19:19 +00:00
});
await new Promise<void>((resolve) => {
2025-05-26 12:23:19 +00:00
interruptServer.listen(2602, () => resolve());
2025-05-24 16:19:19 +00:00
});
const smtpClient = createSmtpClient({
host: '127.0.0.1',
2025-05-26 12:23:19 +00:00
port: 2602,
2025-05-24 16:19:19 +00:00
secure: false,
2025-05-26 12:23:19 +00:00
connectionTimeout: 2000,
2025-05-24 16:19:19 +00:00
debug: true
});
2025-05-26 12:23:19 +00:00
// Should handle the interruption gracefully
const result = await smtpClient.verify();
expect(result).toBeFalse();
console.log('✅ Handled network interruption during verification');
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
await new Promise<void>((resolve) => {
interruptServer.close(() => resolve());
});
2025-05-24 16:19:19 +00:00
});
2025-05-26 12:23:19 +00:00
tap.test('CREL-02: Recovery after brief network glitch', async () => {
2025-05-24 16:19:19 +00:00
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
2025-05-26 12:23:19 +00:00
// Send email successfully
const email1 = new Email({
2025-05-24 16:19:19 +00:00
from: 'sender@example.com',
to: ['recipient@example.com'],
2025-05-26 12:23:19 +00:00
subject: 'Before Glitch',
text: 'First email before network glitch'
2025-05-24 16:19:19 +00:00
});
2025-05-26 12:23:19 +00:00
const result1 = await smtpClient.sendMail(email1);
expect(result1.success).toBeTrue();
console.log('First email sent successfully');
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
// Close to simulate brief network issue
2025-05-24 16:19:19 +00:00
await smtpClient.close();
2025-05-26 12:23:19 +00:00
console.log('Simulating brief network glitch...');
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
// Wait a moment
await new Promise(resolve => setTimeout(resolve, 500));
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
// Try to send another email - should reconnect automatically
const email2 = new Email({
2025-05-24 16:19:19 +00:00
from: 'sender@example.com',
to: ['recipient@example.com'],
2025-05-26 12:23:19 +00:00
subject: 'After Glitch',
text: 'Second email after network recovery'
2025-05-24 16:19:19 +00:00
});
2025-05-26 12:23:19 +00:00
const result2 = await smtpClient.sendMail(email2);
expect(result2.success).toBeTrue();
console.log('✅ Recovered from network glitch successfully');
2025-05-24 16:19:19 +00:00
await smtpClient.close();
});
2025-05-26 12:23:19 +00:00
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<void>((resolve) => {
unresponsiveServer.listen(2604, () => resolve());
});
2025-05-24 16:19:19 +00:00
const smtpClient = createSmtpClient({
2025-05-26 12:23:19 +00:00
host: '127.0.0.1',
port: 2604,
2025-05-24 16:19:19 +00:00
secure: false,
2025-05-26 12:23:19 +00:00
connectionTimeout: 2000, // Short timeout to detect unresponsiveness
2025-05-24 16:19:19 +00:00
debug: true
});
2025-05-26 12:23:19 +00:00
// Should timeout when server doesn't respond
const result = await smtpClient.verify();
expect(result).toBeFalse();
console.log('✅ Detected unresponsive server');
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
await new Promise<void>((resolve) => {
unresponsiveServer.close(() => resolve());
2025-05-24 16:19:19 +00:00
});
});
2025-05-26 12:23:19 +00:00
tap.test('CREL-02: Handle large email successfully', async () => {
2025-05-24 16:19:19 +00:00
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
2025-05-26 12:23:19 +00:00
connectionTimeout: 10000,
socketTimeout: 10000,
2025-05-24 16:19:19 +00:00
debug: true
});
2025-05-26 12:23:19 +00:00
// Create a large email
const largeText = 'x'.repeat(10000); // 10KB of text
const email = new Email({
2025-05-24 16:19:19 +00:00
from: 'sender@example.com',
2025-05-26 12:23:19 +00:00
to: ['recipient@example.com'],
subject: 'Large Email Test',
text: largeText
});
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
// Should complete successfully despite size
const result = await smtpClient.sendMail(email);
expect(result.success).toBeTrue();
console.log('✅ Large email sent successfully');
2025-05-24 16:19:19 +00:00
await smtpClient.close();
});
2025-05-26 12:23:19 +00:00
tap.test('CREL-02: Rapid reconnection after interruption', async () => {
2025-05-24 16:19:19 +00:00
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
2025-05-26 12:23:19 +00:00
connectionTimeout: 5000,
2025-05-24 16:19:19 +00:00
debug: true
});
2025-05-26 12:23:19 +00:00
// Rapid cycle of verify, close, verify
for (let i = 0; i < 3; i++) {
const result = await smtpClient.verify();
expect(result).toBeTrue();
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
await smtpClient.close();
console.log(`Rapid cycle ${i + 1} completed`);
2025-05-24 16:19:19 +00:00
2025-05-26 12:23:19 +00:00
// Very short delay
await new Promise(resolve => setTimeout(resolve, 50));
2025-05-24 16:19:19 +00:00
}
2025-05-26 12:23:19 +00:00
console.log('✅ Rapid reconnection handled successfully');
2025-05-24 16:19:19 +00:00
});
tap.test('cleanup test SMTP server', async () => {
if (testServer) {
2025-05-26 12:23:19 +00:00
await stopTestServer(testServer);
2025-05-24 16:19:19 +00:00
}
});
export default tap.start();