Files
mailer/test/suite/smtpserver_commands/test.cmd-13.quit-command.test.ts
Juergen Kunz 7ecdd9f1e4 Add comprehensive SMTP command tests for RCPT TO, DATA, QUIT, TLS, and basic email sending
- Implement CMD-03 tests for RCPT TO command, validating recipient addresses, handling multiple recipients, and enforcing command sequence.
- Implement CMD-04 tests for DATA command, ensuring proper email content transmission, handling of dot-stuffing, large messages, and correct command sequence.
- Implement CMD-13 tests for QUIT command, verifying graceful connection termination and idempotency.
- Implement CM-01 tests for TLS connections, including STARTTLS capability and direct TLS connections.
- Implement EP-01 tests for basic email sending, covering complete SMTP transaction flow, MIME attachments, HTML emails, custom headers, and minimal emails.
2025-10-28 10:11:34 +00:00

177 lines
4.7 KiB
TypeScript

/**
* CMD-13: QUIT Command Tests
* Tests SMTP QUIT command for graceful connection termination
*/
import { assert, assertMatch } from '@std/assert';
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.ts';
import {
connectToSmtp,
waitForGreeting,
sendSmtpCommand,
closeSmtpConnection,
} from '../../helpers/utils.ts';
const TEST_PORT = 25255;
let testServer: ITestServer;
Deno.test({
name: 'CMD-13: Setup - Start SMTP server',
async fn() {
testServer = await startTestServer({ port: TEST_PORT });
assert(testServer, 'Test server should be created');
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: QUIT - gracefully closes connection',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
// Send QUIT command
const response = await sendSmtpCommand(conn, 'QUIT', '221');
assertMatch(response, /^221/, 'Should respond with 221 Service closing');
assert(response.includes('Service closing'), 'Should indicate service is closing');
console.log('✓ QUIT command received 221 response');
} finally {
try {
conn.close();
} catch {
// Connection may already be closed by server
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: QUIT - works after MAIL FROM',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
await sendSmtpCommand(conn, 'MAIL FROM:<sender@example.com>', '250');
// QUIT should work at any point
const response = await sendSmtpCommand(conn, 'QUIT', '221');
assertMatch(response, /^221/, 'Should respond with 221');
console.log('✓ QUIT works after MAIL FROM');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: QUIT - works after complete transaction',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
await sendSmtpCommand(conn, 'MAIL FROM:<sender@example.com>', '250');
await sendSmtpCommand(conn, 'RCPT TO:<recipient@example.com>', '250');
// QUIT should work after a complete transaction setup
const response = await sendSmtpCommand(conn, 'QUIT', '221');
assertMatch(response, /^221/, 'Should respond with 221');
console.log('✓ QUIT works after complete transaction');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: QUIT - can be called multiple times (idempotent)',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
// First QUIT
const response1 = await sendSmtpCommand(conn, 'QUIT', '221');
assertMatch(response1, /^221/, 'First QUIT should respond with 221');
// Try second QUIT (connection might be closed, so catch error)
try {
const response2 = await sendSmtpCommand(conn, 'QUIT');
// If we get here, server allowed second QUIT
console.log('⚠️ Server allows multiple QUIT commands');
} catch (error) {
// This is expected - connection should be closed after first QUIT
console.log('✓ Connection closed after first QUIT (expected)');
}
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: QUIT - works without EHLO (immediate quit)',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
// QUIT immediately after greeting
const response = await sendSmtpCommand(conn, 'QUIT', '221');
assertMatch(response, /^221/, 'Should respond with 221 even without EHLO');
console.log('✓ QUIT works without EHLO');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-13: Cleanup - Stop SMTP server',
async fn() {
await stopTestServer(testServer);
},
sanitizeResources: false,
sanitizeOps: false,
});