feat(tests): Port CMD-06 RSET, SEC-06 IP Reputation, and ERR-01 Syntax Error tests

- Ported CMD-06 RSET Command tests with 8 passing tests covering transaction resets and recipient clearing.
- Ported SEC-06 IP Reputation tests with 7 passing tests validating infrastructure and legitimate traffic acceptance.
- Ported ERR-01 Syntax Error tests with 10 passing tests for handling invalid commands and syntax errors.
- Updated README files to reflect the new test statuses and coverage.
- Added detailed test cases for handling invalid sequences in ERR-02 tests.
This commit is contained in:
2025-10-28 10:47:05 +00:00
parent 7ecdd9f1e4
commit 0018b19164
6 changed files with 1126 additions and 21 deletions

View File

@@ -0,0 +1,225 @@
/**
* CMD-06: RSET Command Tests
* Tests SMTP RSET command for transaction reset
*/
import { assert, assertEquals, 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 = 25259;
let testServer: ITestServer;
Deno.test({
name: 'CMD-06: 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-06: RSET - resets transaction 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');
// Send RSET
const rsetResponse = await sendSmtpCommand(conn, 'RSET', '250');
assert(rsetResponse.includes('250'), 'RSET should respond with 250 OK');
// After RSET, should be able to send new MAIL FROM
const mailFromResponse = await sendSmtpCommand(conn, 'MAIL FROM:<newsender@example.com>', '250');
assert(mailFromResponse.includes('250'), 'Should accept MAIL FROM after RSET');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ RSET successfully resets transaction after MAIL FROM');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: RSET - resets transaction after RCPT TO',
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');
// Send RSET
const rsetResponse = await sendSmtpCommand(conn, 'RSET', '250');
assert(rsetResponse.includes('250'), 'RSET should respond with 250 OK');
// After RSET, RCPT TO should fail (need MAIL FROM first)
const rcptToResponse = await sendSmtpCommand(conn, 'RCPT TO:<newrecipient@example.com>');
assertMatch(rcptToResponse, /^503/, 'Should reject RCPT TO without MAIL FROM after RSET');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ RSET clears transaction state requiring new MAIL FROM');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: RSET - handles multiple consecutive RSET commands',
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');
// Send multiple RSETs
const rset1 = await sendSmtpCommand(conn, 'RSET', '250');
assert(rset1.includes('250'), 'First RSET should succeed');
const rset2 = await sendSmtpCommand(conn, 'RSET', '250');
assert(rset2.includes('250'), 'Second RSET should succeed');
const rset3 = await sendSmtpCommand(conn, 'RSET', '250');
assert(rset3.includes('250'), 'Third RSET should succeed');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ Multiple consecutive RSET commands work (idempotent)');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: RSET - works without active transaction',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
// Send RSET without any transaction
const rsetResponse = await sendSmtpCommand(conn, 'RSET', '250');
assert(rsetResponse.includes('250'), 'RSET should work even without active transaction');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ RSET works without active transaction');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: RSET - clears all recipients',
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');
// Add multiple recipients
await sendSmtpCommand(conn, 'RCPT TO:<recipient1@example.com>', '250');
await sendSmtpCommand(conn, 'RCPT TO:<recipient2@example.com>', '250');
await sendSmtpCommand(conn, 'RCPT TO:<recipient3@example.com>', '250');
// Send RSET
const rsetResponse = await sendSmtpCommand(conn, 'RSET', '250');
assert(rsetResponse.includes('250'), 'RSET should respond with 250 OK');
// After RSET, DATA should fail (no recipients)
const dataResponse = await sendSmtpCommand(conn, 'DATA');
assertMatch(dataResponse, /^503/, 'DATA should fail without recipients after RSET');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ RSET clears all recipients from transaction');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: RSET - ignores parameters',
async fn() {
const conn = await connectToSmtp('localhost', TEST_PORT);
try {
await waitForGreeting(conn);
await sendSmtpCommand(conn, 'EHLO test.example.com', '250');
// Send RSET with parameters (should be ignored)
const rsetResponse = await sendSmtpCommand(conn, 'RSET ignored parameter', '250');
assert(rsetResponse.includes('250'), 'RSET should ignore parameters and respond with 250 OK');
await sendSmtpCommand(conn, 'QUIT', '221');
console.log('✓ RSET ignores parameters as per RFC');
} finally {
try {
conn.close();
} catch {
// Ignore
}
}
},
sanitizeResources: false,
sanitizeOps: false,
});
Deno.test({
name: 'CMD-06: Cleanup - Stop SMTP server',
async fn() {
await stopTestServer(testServer);
},
sanitizeResources: false,
sanitizeOps: false,
});