166 lines
4.8 KiB
TypeScript
166 lines
4.8 KiB
TypeScript
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||
|
import { startTestServer, stopTestServer, type ITestServer } from '../../helpers/server.loader.js';
|
||
|
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js';
|
||
|
import type { SmtpClient } from '../../../ts/mail/delivery/smtpclient/smtp-client.js';
|
||
|
|
||
|
let testServer: ITestServer;
|
||
|
let smtpClient: SmtpClient;
|
||
|
|
||
|
tap.test('setup - start SMTP server for command tests', async () => {
|
||
|
testServer = await startTestServer({
|
||
|
port: 2540,
|
||
|
tlsEnabled: false,
|
||
|
authRequired: false
|
||
|
});
|
||
|
|
||
|
expect(testServer.port).toEqual(2540);
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should send EHLO with custom domain', async () => {
|
||
|
const startTime = Date.now();
|
||
|
|
||
|
try {
|
||
|
// Create SMTP client with custom domain
|
||
|
smtpClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
domain: 'mail.example.com', // Custom EHLO domain
|
||
|
connectionTimeout: 5000,
|
||
|
debug: true
|
||
|
});
|
||
|
|
||
|
// Verify connection (which sends EHLO)
|
||
|
const isConnected = await smtpClient.verify();
|
||
|
expect(isConnected).toBeTrue();
|
||
|
|
||
|
const duration = Date.now() - startTime;
|
||
|
console.log(`✅ EHLO command sent with custom domain in ${duration}ms`);
|
||
|
|
||
|
} catch (error) {
|
||
|
const duration = Date.now() - startTime;
|
||
|
console.error(`❌ EHLO command failed after ${duration}ms:`, error);
|
||
|
throw error;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should use default domain when not specified', async () => {
|
||
|
const defaultClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
// No domain specified - should use default
|
||
|
connectionTimeout: 5000,
|
||
|
debug: true
|
||
|
});
|
||
|
|
||
|
const isConnected = await defaultClient.verify();
|
||
|
expect(isConnected).toBeTrue();
|
||
|
|
||
|
await defaultClient.close();
|
||
|
console.log('✅ EHLO sent with default domain');
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should handle international domains', async () => {
|
||
|
const intlClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
domain: 'mail.例え.jp', // International domain
|
||
|
connectionTimeout: 5000,
|
||
|
debug: true
|
||
|
});
|
||
|
|
||
|
const isConnected = await intlClient.verify();
|
||
|
expect(isConnected).toBeTrue();
|
||
|
|
||
|
await intlClient.close();
|
||
|
console.log('✅ EHLO sent with international domain');
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should fall back to HELO if needed', async () => {
|
||
|
// Most modern servers support EHLO, but client should handle HELO fallback
|
||
|
const heloClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
domain: 'legacy.example.com',
|
||
|
connectionTimeout: 5000,
|
||
|
debug: true
|
||
|
});
|
||
|
|
||
|
// The client should handle EHLO/HELO automatically
|
||
|
const isConnected = await heloClient.verify();
|
||
|
expect(isConnected).toBeTrue();
|
||
|
|
||
|
await heloClient.close();
|
||
|
console.log('✅ EHLO/HELO fallback mechanism working');
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should parse server capabilities', async () => {
|
||
|
const capClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
connectionTimeout: 5000,
|
||
|
debug: true
|
||
|
});
|
||
|
|
||
|
await capClient.verify();
|
||
|
|
||
|
// After EHLO, client should have server capabilities
|
||
|
// This is internal to the client, but we can verify by attempting
|
||
|
// operations that depend on capabilities
|
||
|
|
||
|
const poolStatus = capClient.getPoolStatus();
|
||
|
expect(poolStatus.total).toBeGreaterThanOrEqual(1);
|
||
|
|
||
|
await capClient.close();
|
||
|
console.log('✅ Server capabilities parsed from EHLO response');
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should handle very long domain names', async () => {
|
||
|
const longDomain = 'very-long-subdomain.with-many-parts.and-labels.example.com';
|
||
|
|
||
|
const longDomainClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
domain: longDomain,
|
||
|
connectionTimeout: 5000
|
||
|
});
|
||
|
|
||
|
const isConnected = await longDomainClient.verify();
|
||
|
expect(isConnected).toBeTrue();
|
||
|
|
||
|
await longDomainClient.close();
|
||
|
console.log('✅ Long domain name handled correctly');
|
||
|
});
|
||
|
|
||
|
tap.test('CCMD-01: EHLO/HELO - should reconnect with EHLO after disconnect', async () => {
|
||
|
// First connection
|
||
|
await smtpClient.verify();
|
||
|
expect(smtpClient.isConnected()).toBeTrue();
|
||
|
|
||
|
// Close connection
|
||
|
await smtpClient.close();
|
||
|
expect(smtpClient.isConnected()).toBeFalse();
|
||
|
|
||
|
// Reconnect - should send EHLO again
|
||
|
const isReconnected = await smtpClient.verify();
|
||
|
expect(isReconnected).toBeTrue();
|
||
|
|
||
|
console.log('✅ EHLO sent correctly on reconnection');
|
||
|
});
|
||
|
|
||
|
tap.test('cleanup - close SMTP client', async () => {
|
||
|
if (smtpClient && smtpClient.isConnected()) {
|
||
|
await smtpClient.close();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
tap.test('cleanup - stop SMTP server', async () => {
|
||
|
await stopTestServer(testServer);
|
||
|
});
|
||
|
|
||
|
tap.start();
|