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 * as net from 'net'; import * as os from 'os'; let testServer: ITestServer; tap.test('setup test SMTP server', async () => { testServer = await startTestServer({ port: 2535, tlsEnabled: false, authRequired: false }); expect(testServer).toBeTruthy(); expect(testServer.port).toEqual(2535); }); tap.test('CCM-09: Check system IPv6 support', async () => { const networkInterfaces = os.networkInterfaces(); let hasIPv6 = false; for (const interfaceName in networkInterfaces) { const interfaces = networkInterfaces[interfaceName]; if (interfaces) { for (const iface of interfaces) { if (iface.family === 'IPv6' && !iface.internal) { hasIPv6 = true; console.log(`Found IPv6 address: ${iface.address} on ${interfaceName}`); } } } } console.log(`System has IPv6 support: ${hasIPv6}`); }); tap.test('CCM-09: IPv4 connection test', async () => { const smtpClient = createSmtpClient({ host: '127.0.0.1', // Explicit IPv4 port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); // Test connection using verify const verified = await smtpClient.verify(); expect(verified).toBeTrue(); console.log('Successfully connected via IPv4'); await smtpClient.close(); }); tap.test('CCM-09: IPv6 connection test (if supported)', async () => { // Check if IPv6 is available const hasIPv6 = await new Promise((resolve) => { const testSocket = net.createConnection({ host: '::1', port: 1, // Any port, will fail but tells us if IPv6 works timeout: 100 }); testSocket.on('error', (err: any) => { // ECONNREFUSED means IPv6 works but port is closed (expected) // ENETUNREACH or EAFNOSUPPORT means IPv6 not available resolve(err.code === 'ECONNREFUSED'); }); testSocket.on('connect', () => { testSocket.end(); resolve(true); }); }); if (!hasIPv6) { console.log('IPv6 not available on this system, skipping IPv6 tests'); return; } // Try IPv6 connection const smtpClient = createSmtpClient({ host: '::1', // IPv6 loopback port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); try { const verified = await smtpClient.verify(); if (verified) { console.log('Successfully connected via IPv6'); await smtpClient.close(); } else { console.log('IPv6 connection failed (server may not support IPv6)'); } } catch (error: any) { console.log('IPv6 connection failed (server may not support IPv6):', error.message); } }); tap.test('CCM-09: Hostname resolution preference', async () => { // Test that client can handle hostnames that resolve to both IPv4 and IPv6 const smtpClient = createSmtpClient({ host: 'localhost', // Should resolve to both 127.0.0.1 and ::1 port: testServer.port, secure: false, connectionTimeout: 5000, debug: true }); const verified = await smtpClient.verify(); expect(verified).toBeTrue(); console.log('Successfully connected to localhost'); await smtpClient.close(); }); tap.test('CCM-09: Happy Eyeballs algorithm simulation', async () => { // Test connecting to multiple addresses with preference const addresses = ['127.0.0.1', '::1', 'localhost']; const results: Array<{ address: string; time: number; success: boolean }> = []; for (const address of addresses) { const startTime = Date.now(); const smtpClient = createSmtpClient({ host: address, port: testServer.port, secure: false, connectionTimeout: 1000, debug: false }); try { const verified = await smtpClient.verify(); const elapsed = Date.now() - startTime; results.push({ address, time: elapsed, success: verified }); if (verified) { await smtpClient.close(); } } catch (error) { const elapsed = Date.now() - startTime; results.push({ address, time: elapsed, success: false }); } } console.log('Connection race results:'); results.forEach(r => { console.log(` ${r.address}: ${r.success ? 'SUCCESS' : 'FAILED'} in ${r.time}ms`); }); // At least one should succeed const successfulConnections = results.filter(r => r.success); expect(successfulConnections.length).toBeGreaterThan(0); }); tap.test('cleanup test SMTP server', async () => { if (testServer) { await stopTestServer(testServer); } }); export default tap.start();