update
This commit is contained in:
211
test/suite/server.loader.ts
Normal file
211
test/suite/server.loader.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Test server loader for SMTP test suite
|
||||
* Provides simplified server lifecycle management for tests
|
||||
*/
|
||||
|
||||
import { DcRouter } from '../../ts/classes.dcrouter.js';
|
||||
import { UnifiedEmailServer } from '../../ts/mail/routing/classes.unified.email.server.js';
|
||||
import { createSmtpServer } from '../../ts/mail/delivery/smtpserver/index.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as net from 'net';
|
||||
|
||||
let activeServer = null;
|
||||
let activePort = null;
|
||||
|
||||
/**
|
||||
* Start test server on default port 2525
|
||||
*/
|
||||
async function startTestServer(port = 2525) {
|
||||
if (activeServer) {
|
||||
console.log('Test server already running, stopping it first...');
|
||||
await stopTestServer();
|
||||
}
|
||||
|
||||
console.log(`Starting test SMTP server on port ${port}...`);
|
||||
|
||||
try {
|
||||
// Create a minimal email server for testing
|
||||
const mockEmailServer = {
|
||||
processEmailByMode: async (emailData) => {
|
||||
console.log('📧 Processed test email:', emailData.subject || 'No subject');
|
||||
return emailData;
|
||||
}
|
||||
};
|
||||
|
||||
// Load test certificates if available
|
||||
let key = '';
|
||||
let cert = '';
|
||||
try {
|
||||
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
||||
key = fs.readFileSync(path.join(__dirname, '../../../test/smtp-prod/certs/test.key'), 'utf8');
|
||||
cert = fs.readFileSync(path.join(__dirname, '../../../test/smtp-prod/certs/test.cert'), 'utf8');
|
||||
} catch (e) {
|
||||
console.log('Test certificates not found, running without TLS');
|
||||
}
|
||||
|
||||
// SMTP server options
|
||||
const smtpOptions = {
|
||||
port: port,
|
||||
hostname: 'localhost',
|
||||
key: key,
|
||||
cert: cert,
|
||||
maxConnections: 100,
|
||||
size: 10 * 1024 * 1024, // 10MB
|
||||
maxRecipients: 100,
|
||||
socketTimeout: 30000,
|
||||
connectionTimeout: 60000,
|
||||
cleanupInterval: 300000,
|
||||
auth: false
|
||||
};
|
||||
|
||||
// Create and start SMTP server
|
||||
const smtpServer = createSmtpServer(mockEmailServer, smtpOptions);
|
||||
await smtpServer.listen();
|
||||
|
||||
activeServer = smtpServer;
|
||||
activePort = port;
|
||||
|
||||
// Wait for server to be ready
|
||||
await waitForServerReady('localhost', port, 10000);
|
||||
|
||||
console.log(`✅ Test SMTP server started on port ${port}`);
|
||||
return smtpServer;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to start test server:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop test server
|
||||
*/
|
||||
async function stopTestServer() {
|
||||
if (!activeServer) {
|
||||
console.log('No active test server to stop');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Stopping test SMTP server on port ${activePort}...`);
|
||||
|
||||
try {
|
||||
if (activeServer.close && typeof activeServer.close === 'function') {
|
||||
await activeServer.close();
|
||||
} else if (activeServer.destroy && typeof activeServer.destroy === 'function') {
|
||||
await activeServer.destroy();
|
||||
} else if (activeServer.stop && typeof activeServer.stop === 'function') {
|
||||
await activeServer.stop();
|
||||
}
|
||||
|
||||
// Force close any remaining connections
|
||||
if (activeServer._connections) {
|
||||
for (const conn of activeServer._connections) {
|
||||
if (conn && !conn.destroyed) {
|
||||
conn.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activeServer = null;
|
||||
const port = activePort;
|
||||
activePort = null;
|
||||
|
||||
// Wait for port to be free
|
||||
await waitForPortFree(port, 3000);
|
||||
|
||||
console.log(`✅ Test SMTP server stopped`);
|
||||
} catch (error) {
|
||||
console.error('Error stopping test server:', error);
|
||||
activeServer = null;
|
||||
activePort = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for server to be ready to accept connections
|
||||
*/
|
||||
async function waitForServerReady(hostname, port, timeout) {
|
||||
const startTime = Date.now();
|
||||
const maxRetries = 20;
|
||||
let retries = 0;
|
||||
|
||||
while (retries < maxRetries) {
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const socket = net.createConnection({ port, host: hostname });
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.end();
|
||||
resolve();
|
||||
});
|
||||
|
||||
socket.on('error', (error) => {
|
||||
socket.destroy();
|
||||
reject(error);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
socket.destroy();
|
||||
reject(new Error('Connection timeout'));
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
return; // Server is ready
|
||||
|
||||
} catch (error) {
|
||||
retries++;
|
||||
|
||||
if (Date.now() - startTime > timeout) {
|
||||
throw new Error(`Server did not become ready within ${timeout}ms`);
|
||||
}
|
||||
|
||||
// Wait before retrying
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Server did not become ready after ${maxRetries} retries`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for port to be free
|
||||
*/
|
||||
async function waitForPortFree(port, timeout) {
|
||||
const startTime = Date.now();
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const isFree = await isPortFree(port);
|
||||
if (isFree) {
|
||||
return true;
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if port is free
|
||||
*/
|
||||
async function isPortFree(port) {
|
||||
return new Promise((resolve) => {
|
||||
const server = net.createServer();
|
||||
|
||||
server.listen(port, () => {
|
||||
server.close(() => {
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
|
||||
server.on('error', () => {
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Export functions
|
||||
export {
|
||||
startTestServer,
|
||||
stopTestServer
|
||||
};
|
||||
Reference in New Issue
Block a user