import { tap, expect } from '@git.zone/tstest/tapbundle'; import { RustSecurityBridge, BridgeState } from '../ts/security/classes.rustsecuritybridge.js'; import type { ISmtpSendOptions, ISmtpPoolStatus } from '../ts/security/classes.rustsecuritybridge.js'; let bridge: RustSecurityBridge; tap.test('Rust SMTP Client - should start bridge', async () => { RustSecurityBridge.resetInstance(); bridge = RustSecurityBridge.getInstance(); const ok = await bridge.start(); if (!ok) { console.log('WARNING: Rust binary not available — skipping Rust SMTP client tests'); console.log('Build it with: cd rust && cargo build --release'); } expect(typeof ok).toEqual('boolean'); }); tap.test('Rust SMTP Client - getSmtpPoolStatus returns valid structure', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } const status: ISmtpPoolStatus = await bridge.getSmtpPoolStatus(); expect(status).toBeTruthy(); expect(status.pools).toBeTruthy(); expect(typeof status.pools).toEqual('object'); }); tap.test('Rust SMTP Client - verifySmtpConnection with unreachable host', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } try { // Use a non-routable IP to test connection failure handling const result = await bridge.verifySmtpConnection({ host: '192.0.2.1', // TEST-NET-1 (RFC 5737) - guaranteed unreachable port: 25, secure: false, domain: 'test.example.com', }); // If it returns rather than throwing, reachable should be false expect(result.reachable).toBeFalse(); } catch (err) { // Connection errors are expected for unreachable hosts expect(err).toBeTruthy(); expect(err.message || String(err)).toBeTruthy(); } }); tap.test('Rust SMTP Client - sendEmail with connection refused error', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } const opts: ISmtpSendOptions = { host: '127.0.0.1', port: 52599, // random high port - should be refused secure: false, domain: 'test.example.com', email: { from: 'sender@example.com', to: ['recipient@example.com'], subject: 'Test email', text: 'This is a test.', }, connectionTimeoutSecs: 5, socketTimeoutSecs: 5, }; try { await bridge.sendOutboundEmail(opts); // Should not succeed — no server is listening throw new Error('Expected sendEmail to fail on connection refused'); } catch (err) { // We expect a connection error expect(err).toBeTruthy(); const msg = err.message || String(err); expect(msg.length).toBeGreaterThan(0); } }); tap.test('Rust SMTP Client - closeSmtpPool cleans up', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } // Should not throw, even when no pools exist await bridge.closeSmtpPool(); // Verify pool status is empty after close const status = await bridge.getSmtpPoolStatus(); expect(status.pools).toBeTruthy(); const poolKeys = Object.keys(status.pools); expect(poolKeys.length).toEqual(0); }); tap.test('Rust SMTP Client - stop bridge', async () => { if (!bridge.running) { console.log('SKIP: bridge not running'); return; } await bridge.stop(); expect(bridge.state).toEqual(BridgeState.Stopped); }); export default tap.start();