dcrouter/test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts

290 lines
8.8 KiB
TypeScript
Raw Normal View History

2025-05-24 16:19:19 +00:00
import { tap, expect } from '@git.zone/tstest/tapbundle';
import { startTestSmtpServer } from '../../helpers/server.loader.js';
import { createSmtpClient } from '../../helpers/smtp.client.js';
let testServer: any;
tap.test('setup test SMTP server', async () => {
testServer = await startTestSmtpServer();
expect(testServer).toBeTruthy();
expect(testServer.port).toBeGreaterThan(0);
});
tap.test('CCMD-08: Basic RSET command', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Send RSET command
const rsetResponse = await smtpClient.sendCommand('RSET');
// Verify response
expect(rsetResponse).toInclude('250');
expect(rsetResponse).toMatch(/reset|ok/i);
console.log(`RSET response: ${rsetResponse.trim()}`);
await smtpClient.close();
});
tap.test('CCMD-08: RSET after MAIL FROM', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Start transaction
const mailResponse = await smtpClient.sendCommand('MAIL FROM:<sender@example.com>');
expect(mailResponse).toInclude('250');
// Reset transaction
const rsetResponse = await smtpClient.sendCommand('RSET');
expect(rsetResponse).toInclude('250');
// Verify transaction was reset by trying RCPT TO without MAIL FROM
const rcptResponse = await smtpClient.sendCommand('RCPT TO:<recipient@example.com>');
expect(rcptResponse).toMatch(/[45]\d\d/); // Should fail
await smtpClient.close();
});
tap.test('CCMD-08: RSET after multiple recipients', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Build up a transaction with multiple recipients
await smtpClient.sendCommand('MAIL FROM:<sender@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient1@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient2@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient3@example.com>');
console.log('Transaction built with 3 recipients');
// Reset the transaction
const rsetResponse = await smtpClient.sendCommand('RSET');
expect(rsetResponse).toInclude('250');
// Start a new transaction to verify reset
const newMailResponse = await smtpClient.sendCommand('MAIL FROM:<newsender@example.com>');
expect(newMailResponse).toInclude('250');
const newRcptResponse = await smtpClient.sendCommand('RCPT TO:<newrecipient@example.com>');
expect(newRcptResponse).toInclude('250');
console.log('Successfully started new transaction after RSET');
await smtpClient.sendCommand('RSET');
await smtpClient.close();
});
tap.test('CCMD-08: RSET during DATA phase', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Start transaction
await smtpClient.sendCommand('MAIL FROM:<sender@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient@example.com>');
// Enter DATA phase
const dataResponse = await smtpClient.sendCommand('DATA');
expect(dataResponse).toInclude('354');
// Try RSET during DATA (should fail or be queued)
// Most servers will interpret this as message content
await smtpClient.sendCommand('RSET');
// Complete the DATA phase
const endDataResponse = await smtpClient.sendCommand('.');
expect(endDataResponse).toInclude('250');
// Now RSET should work
const rsetResponse = await smtpClient.sendCommand('RSET');
expect(rsetResponse).toInclude('250');
await smtpClient.close();
});
tap.test('CCMD-08: Multiple RSET commands', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Send multiple RSET commands
for (let i = 0; i < 5; i++) {
const rsetResponse = await smtpClient.sendCommand('RSET');
expect(rsetResponse).toInclude('250');
console.log(`RSET ${i + 1}: ${rsetResponse.trim()}`);
}
// Should still be able to start a transaction
const mailResponse = await smtpClient.sendCommand('MAIL FROM:<sender@example.com>');
expect(mailResponse).toInclude('250');
await smtpClient.sendCommand('RSET');
await smtpClient.close();
});
tap.test('CCMD-08: RSET with pipelining', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
enablePipelining: true,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Pipeline commands including RSET
const pipelinedCommands = [
smtpClient.sendCommand('MAIL FROM:<sender@example.com>'),
smtpClient.sendCommand('RCPT TO:<recipient@example.com>'),
smtpClient.sendCommand('RSET'),
smtpClient.sendCommand('MAIL FROM:<newsender@example.com>'),
smtpClient.sendCommand('RCPT TO:<newrecipient@example.com>')
];
const responses = await Promise.all(pipelinedCommands);
// Check responses
expect(responses[0]).toInclude('250'); // MAIL FROM
expect(responses[1]).toInclude('250'); // RCPT TO
expect(responses[2]).toInclude('250'); // RSET
expect(responses[3]).toInclude('250'); // New MAIL FROM
expect(responses[4]).toInclude('250'); // New RCPT TO
console.log('Successfully pipelined commands with RSET');
await smtpClient.sendCommand('RSET');
await smtpClient.close();
});
tap.test('CCMD-08: RSET state verification', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: true
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
// Build complex state
await smtpClient.sendCommand('MAIL FROM:<sender@example.com> SIZE=1000');
await smtpClient.sendCommand('RCPT TO:<recipient1@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient2@example.com>');
console.log('Built transaction state with SIZE parameter and 2 recipients');
// Reset
const rsetResponse = await smtpClient.sendCommand('RSET');
expect(rsetResponse).toInclude('250');
// Verify all state is cleared
// 1. Can't add recipients without MAIL FROM
const rcptResponse = await smtpClient.sendCommand('RCPT TO:<test@example.com>');
expect(rcptResponse).toMatch(/[45]\d\d/);
// 2. Can start fresh transaction
const newMailResponse = await smtpClient.sendCommand('MAIL FROM:<different@example.com>');
expect(newMailResponse).toInclude('250');
// 3. Previous recipients are not remembered
const dataResponse = await smtpClient.sendCommand('DATA');
expect(dataResponse).toMatch(/[45]\d\d/); // Should fail - no recipients
await smtpClient.sendCommand('RSET');
await smtpClient.close();
});
tap.test('CCMD-08: RSET performance impact', async () => {
const smtpClient = createSmtpClient({
host: testServer.hostname,
port: testServer.port,
secure: false,
connectionTimeout: 5000,
debug: false // Quiet for performance test
});
await smtpClient.connect();
await smtpClient.sendCommand('EHLO testclient.example.com');
const iterations = 20;
const times: number[] = [];
for (let i = 0; i < iterations; i++) {
// Build transaction
await smtpClient.sendCommand('MAIL FROM:<sender@example.com>');
await smtpClient.sendCommand('RCPT TO:<recipient@example.com>');
// Measure RSET time
const startTime = Date.now();
await smtpClient.sendCommand('RSET');
const elapsed = Date.now() - startTime;
times.push(elapsed);
}
// Analyze RSET performance
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
console.log(`RSET performance over ${iterations} iterations:`);
console.log(` Average: ${avgTime.toFixed(2)}ms`);
console.log(` Min: ${minTime}ms`);
console.log(` Max: ${maxTime}ms`);
// RSET should be fast
expect(avgTime).toBeLessThan(100);
await smtpClient.close();
});
tap.test('cleanup test SMTP server', async () => {
if (testServer) {
await testServer.stop();
}
});
export default tap.start();