import { tap, expect } from '@git.zone/tstest/tapbundle'; import { startTestSmtpServer } from '../../helpers/server.loader.js'; import { createSmtpClient } from '../../helpers/smtp.client.js'; import * as net from 'net'; import * as os from 'os'; let testServer: any; tap.test('setup test SMTP server', async () => { testServer = await startTestSmtpServer(); expect(testServer).toBeTruthy(); expect(testServer.port).toBeGreaterThan(0); }); 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 }); let connected = false; let connectionFamily = ''; smtpClient.on('connection', (info: any) => { connected = true; if (info && info.socket) { connectionFamily = info.socket.remoteFamily || ''; } }); smtpClient.on('error', (error: Error) => { console.error('IPv4 connection error:', error.message); }); // Test connection const result = await smtpClient.connect(); expect(result).toBeTruthy(); expect(smtpClient.isConnected()).toBeTruthy(); console.log(`Connected via IPv4, family: ${connectionFamily}`); 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 }); let connected = false; let connectionFamily = ''; smtpClient.on('connection', (info: any) => { connected = true; if (info && info.socket) { connectionFamily = info.socket.remoteFamily || ''; } }); smtpClient.on('error', (error: Error) => { console.error('IPv6 connection error:', error.message); }); try { const result = await smtpClient.connect(); if (result && smtpClient.isConnected()) { console.log(`Connected via IPv6, family: ${connectionFamily}`); await smtpClient.close(); } } catch (error) { 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 }); let connectionInfo: any = null; smtpClient.on('connection', (info: any) => { connectionInfo = info; }); const result = await smtpClient.connect(); expect(result).toBeTruthy(); expect(smtpClient.isConnected()).toBeTruthy(); if (connectionInfo && connectionInfo.socket) { console.log(`Connected to localhost via ${connectionInfo.socket.remoteFamily || 'unknown'}`); console.log(`Local address: ${connectionInfo.socket.localAddress}`); console.log(`Remote address: ${connectionInfo.socket.remoteAddress}`); } 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 connected = await smtpClient.connect(); const elapsed = Date.now() - startTime; results.push({ address, time: elapsed, success: !!connected }); if (connected) { 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 testServer.stop(); } }); export default tap.start();