dcrouter/test/suite/smtpserver_connection/test.cm-03.connection-timeout.ts
2025-05-25 19:05:43 +00:00

134 lines
3.6 KiB
TypeScript

import { tap, expect } from '@git.zone/tstest/tapbundle';
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
import * as plugins from '../../../ts/plugins.js';
const TEST_PORT = 2525;
let testServer: ITestServer;
tap.test('setup - start SMTP server with short timeout', async () => {
testServer = await startTestServer({
port: TEST_PORT,
timeout: 5000 // 5 second timeout for this test
});
await new Promise(resolve => setTimeout(resolve, 1000));
});
tap.test('CM-03: Connection Timeout - idle connections are closed after timeout', async (tools) => {
const startTime = Date.now();
// Create connection
const socket = await new Promise<plugins.net.Socket>((resolve, reject) => {
const client = plugins.net.createConnection({
host: testServer.hostname,
port: testServer.port
});
client.on('connect', () => resolve(client));
client.on('error', reject);
setTimeout(() => reject(new Error('Connection timeout')), 3000);
});
// Wait for greeting
await new Promise<void>((resolve) => {
socket.once('data', (data) => {
const response = data.toString();
expect(response).toInclude('220');
resolve();
});
});
console.log('✅ Connected and received greeting');
// Now stay idle and wait for server to timeout the connection
const disconnectPromise = new Promise<number>((resolve) => {
socket.on('close', () => {
const duration = Date.now() - startTime;
resolve(duration);
});
socket.on('end', () => {
console.log('📡 Server initiated connection close');
});
socket.on('error', (err) => {
console.log('⚠️ Socket error:', err.message);
});
});
// Wait for timeout (should be around 5 seconds)
const duration = await disconnectPromise;
console.log(`⏱️ Connection closed after ${duration}ms`);
// Verify timeout happened within expected range (4-6 seconds)
expect(duration).toBeGreaterThan(4000);
expect(duration).toBeLessThan(7000);
console.log('✅ Connection timeout test passed');
});
tap.test('CM-03: Active connection should not timeout', async () => {
// Create new connection
const socket = plugins.net.createConnection({
host: testServer.hostname,
port: testServer.port
});
await new Promise<void>((resolve) => {
socket.on('connect', resolve);
});
// Wait for greeting
await new Promise<void>((resolve) => {
socket.once('data', resolve);
});
// Keep connection active with NOOP commands
let isConnected = true;
socket.on('close', () => {
isConnected = false;
});
// Send NOOP every 2 seconds for 8 seconds
for (let i = 0; i < 4; i++) {
if (!isConnected) break;
socket.write('NOOP\r\n');
// Wait for response
await new Promise<void>((resolve) => {
socket.once('data', (data) => {
const response = data.toString();
expect(response).toInclude('250');
resolve();
});
});
console.log(`✅ NOOP ${i + 1}/4 successful`);
// Wait 2 seconds before next NOOP
await new Promise(resolve => setTimeout(resolve, 2000));
}
// Connection should still be active
expect(isConnected).toEqual(true);
// Close connection gracefully
socket.write('QUIT\r\n');
await new Promise<void>((resolve) => {
socket.once('data', () => {
socket.end();
resolve();
});
});
console.log('✅ Active connection did not timeout');
});
tap.test('cleanup - stop SMTP server', async () => {
await stopTestServer(testServer);
});
export default tap.start();