204 lines
6.2 KiB
TypeScript
204 lines
6.2 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 { Email } from '../../../ts/mail/core/classes.email.js';
|
|
|
|
let testServer: ITestServer;
|
|
|
|
tap.test('setup test SMTP server', async () => {
|
|
testServer = await startTestServer({
|
|
port: 2576,
|
|
tlsEnabled: false,
|
|
authRequired: false,
|
|
maxConnections: 20 // Allow more connections for concurrent testing
|
|
});
|
|
expect(testServer).toBeTruthy();
|
|
expect(testServer.port).toEqual(2576);
|
|
});
|
|
|
|
tap.test('CEDGE-07: Multiple simultaneous connections', async () => {
|
|
console.log('Testing multiple simultaneous connections');
|
|
|
|
const connectionCount = 5;
|
|
const clients = [];
|
|
|
|
// Create multiple clients
|
|
for (let i = 0; i < connectionCount; i++) {
|
|
const client = createSmtpClient({
|
|
host: testServer.hostname,
|
|
port: testServer.port,
|
|
secure: false,
|
|
connectionTimeout: 5000,
|
|
debug: false, // Reduce noise
|
|
maxConnections: 2
|
|
});
|
|
clients.push(client);
|
|
}
|
|
|
|
// Test concurrent verification
|
|
console.log(` Testing ${connectionCount} concurrent verifications...`);
|
|
const verifyPromises = clients.map(async (client, index) => {
|
|
try {
|
|
const result = await client.verify();
|
|
console.log(` Client ${index + 1}: ${result ? 'Success' : 'Failed'}`);
|
|
return result;
|
|
} catch (error) {
|
|
console.log(` Client ${index + 1}: Error - ${error.message}`);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
const verifyResults = await Promise.all(verifyPromises);
|
|
const successCount = verifyResults.filter(r => r).length;
|
|
console.log(` Verify results: ${successCount}/${connectionCount} successful`);
|
|
|
|
// We expect at least some connections to succeed
|
|
expect(successCount).toBeGreaterThan(0);
|
|
|
|
// Clean up clients
|
|
await Promise.all(clients.map(client => client.close().catch(() => {})));
|
|
});
|
|
|
|
tap.test('CEDGE-07: Concurrent email sending', async () => {
|
|
console.log('Testing concurrent email sending');
|
|
|
|
const smtpClient = createSmtpClient({
|
|
host: testServer.hostname,
|
|
port: testServer.port,
|
|
secure: false,
|
|
connectionTimeout: 5000,
|
|
debug: false,
|
|
maxConnections: 5
|
|
});
|
|
|
|
const emailCount = 10;
|
|
console.log(` Sending ${emailCount} emails concurrently...`);
|
|
|
|
const sendPromises = [];
|
|
for (let i = 0; i < emailCount; i++) {
|
|
const email = new Email({
|
|
from: 'sender@example.com',
|
|
to: [`recipient${i}@example.com`],
|
|
subject: `Concurrent test email ${i + 1}`,
|
|
text: `This is concurrent test email number ${i + 1}`
|
|
});
|
|
|
|
sendPromises.push(
|
|
smtpClient.sendMail(email).then(
|
|
result => {
|
|
console.log(` Email ${i + 1}: Success`);
|
|
return { success: true, result };
|
|
},
|
|
error => {
|
|
console.log(` Email ${i + 1}: Failed - ${error.message}`);
|
|
return { success: false, error };
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
const results = await Promise.all(sendPromises);
|
|
const successCount = results.filter(r => r.success).length;
|
|
console.log(` Send results: ${successCount}/${emailCount} successful`);
|
|
|
|
// We expect a high success rate
|
|
expect(successCount).toBeGreaterThan(emailCount * 0.7); // At least 70% success
|
|
|
|
await smtpClient.close();
|
|
});
|
|
|
|
tap.test('CEDGE-07: Rapid connection cycling', async () => {
|
|
console.log('Testing rapid connection cycling');
|
|
|
|
const cycleCount = 8;
|
|
console.log(` Performing ${cycleCount} rapid connect/disconnect cycles...`);
|
|
|
|
const cyclePromises = [];
|
|
for (let i = 0; i < cycleCount; i++) {
|
|
cyclePromises.push(
|
|
(async () => {
|
|
const client = createSmtpClient({
|
|
host: testServer.hostname,
|
|
port: testServer.port,
|
|
secure: false,
|
|
connectionTimeout: 3000,
|
|
debug: false
|
|
});
|
|
|
|
try {
|
|
const verified = await client.verify();
|
|
console.log(` Cycle ${i + 1}: ${verified ? 'Success' : 'Failed'}`);
|
|
await client.close();
|
|
return verified;
|
|
} catch (error) {
|
|
console.log(` Cycle ${i + 1}: Error - ${error.message}`);
|
|
await client.close().catch(() => {});
|
|
return false;
|
|
}
|
|
})()
|
|
);
|
|
}
|
|
|
|
const cycleResults = await Promise.all(cyclePromises);
|
|
const successCount = cycleResults.filter(r => r).length;
|
|
console.log(` Cycle results: ${successCount}/${cycleCount} successful`);
|
|
|
|
// We expect most cycles to succeed
|
|
expect(successCount).toBeGreaterThan(cycleCount * 0.6); // At least 60% success
|
|
});
|
|
|
|
tap.test('CEDGE-07: Connection pool stress test', async () => {
|
|
console.log('Testing connection pool under stress');
|
|
|
|
const smtpClient = createSmtpClient({
|
|
host: testServer.hostname,
|
|
port: testServer.port,
|
|
secure: false,
|
|
connectionTimeout: 5000,
|
|
debug: false,
|
|
maxConnections: 3,
|
|
maxMessages: 50
|
|
});
|
|
|
|
const stressCount = 15;
|
|
console.log(` Sending ${stressCount} emails to stress connection pool...`);
|
|
|
|
const startTime = Date.now();
|
|
const stressPromises = [];
|
|
|
|
for (let i = 0; i < stressCount; i++) {
|
|
const email = new Email({
|
|
from: 'stress@example.com',
|
|
to: [`stress${i}@example.com`],
|
|
subject: `Stress test ${i + 1}`,
|
|
text: `Connection pool stress test email ${i + 1}`
|
|
});
|
|
|
|
stressPromises.push(
|
|
smtpClient.sendMail(email).then(
|
|
result => ({ success: true, index: i }),
|
|
error => ({ success: false, index: i, error: error.message })
|
|
)
|
|
);
|
|
}
|
|
|
|
const stressResults = await Promise.all(stressPromises);
|
|
const duration = Date.now() - startTime;
|
|
const successCount = stressResults.filter(r => r.success).length;
|
|
|
|
console.log(` Stress results: ${successCount}/${stressCount} successful in ${duration}ms`);
|
|
console.log(` Average: ${Math.round(duration / stressCount)}ms per email`);
|
|
|
|
// Under stress, we still expect reasonable success rate
|
|
expect(successCount).toBeGreaterThan(stressCount * 0.5); // At least 50% success under stress
|
|
|
|
await smtpClient.close();
|
|
});
|
|
|
|
tap.test('cleanup test SMTP server', async () => {
|
|
if (testServer) {
|
|
await stopTestServer(testServer);
|
|
}
|
|
});
|
|
|
|
export default tap.start(); |