update
This commit is contained in:
290
test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts
Normal file
290
test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts
Normal file
@ -0,0 +1,290 @@
|
||||
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();
|
Reference in New Issue
Block a user