533 lines
18 KiB
TypeScript
533 lines
18 KiB
TypeScript
|
import { test } from '@git.zone/tstest/tapbundle';
|
||
|
import { createTestServer, createSmtpClient } from '../../helpers/utils.js';
|
||
|
import { Email } from '../../../ts/mail/core/classes.email.js';
|
||
|
|
||
|
test('CPERF-08: DNS Caching Efficiency Performance Tests', async () => {
|
||
|
console.log('\n🌐 Testing SMTP Client DNS Caching Efficiency');
|
||
|
console.log('=' .repeat(60));
|
||
|
|
||
|
// Scenario 1: DNS Resolution Caching
|
||
|
await test.test('Scenario 1: DNS Resolution Caching', async () => {
|
||
|
console.log('\n🔍 Testing DNS resolution caching performance...');
|
||
|
|
||
|
let dnsLookupCount = 0;
|
||
|
const originalLookup = require('dns').lookup;
|
||
|
|
||
|
// Mock DNS lookup to track calls
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
dnsLookupCount++;
|
||
|
console.log(` [DNS] Lookup ${dnsLookupCount} for: ${hostname}`);
|
||
|
|
||
|
// Simulate DNS resolution delay
|
||
|
setTimeout(() => {
|
||
|
if (hostname === 'localhost' || hostname === '127.0.0.1') {
|
||
|
callback(null, '127.0.0.1', 4);
|
||
|
} else {
|
||
|
callback(null, '127.0.0.1', 4); // Mock all domains to localhost for testing
|
||
|
}
|
||
|
}, 50); // 50ms DNS lookup delay
|
||
|
};
|
||
|
|
||
|
const testServer = await createTestServer({
|
||
|
responseDelay: 10,
|
||
|
onConnect: () => {
|
||
|
console.log(' [Server] Connection established');
|
||
|
}
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
console.log(' Creating SMTP client with connection pooling...');
|
||
|
const smtpClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
pool: true,
|
||
|
maxConnections: 3,
|
||
|
maxMessages: 100,
|
||
|
// DNS caching settings
|
||
|
dnsCache: true,
|
||
|
dnsCacheTtl: 5000 // 5 seconds TTL
|
||
|
});
|
||
|
|
||
|
console.log(' Sending multiple emails to same domain...');
|
||
|
const emails = [];
|
||
|
for (let i = 0; i < 10; i++) {
|
||
|
emails.push(new Email({
|
||
|
from: 'sender@example.com',
|
||
|
to: [`recipient${i}@example.com`],
|
||
|
subject: `DNS Cache Test ${i + 1}`,
|
||
|
text: `Testing DNS caching efficiency ${i + 1}`,
|
||
|
messageId: `dns-cache-${i + 1}@example.com`
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
const startTime = Date.now();
|
||
|
const promises = emails.map((email, index) => {
|
||
|
return smtpClient.sendMail(email).then(result => {
|
||
|
console.log(` ✓ Email ${index + 1} sent successfully`);
|
||
|
return { success: true, result };
|
||
|
}).catch(error => {
|
||
|
console.log(` ✗ Email ${index + 1} failed: ${error.message}`);
|
||
|
return { success: false, error };
|
||
|
});
|
||
|
});
|
||
|
|
||
|
const results = await Promise.all(promises);
|
||
|
const endTime = Date.now();
|
||
|
|
||
|
const successful = results.filter(r => r.success).length;
|
||
|
const totalTime = endTime - startTime;
|
||
|
|
||
|
console.log(` Total DNS lookups performed: ${dnsLookupCount}`);
|
||
|
console.log(` Emails sent: ${emails.length}, Successful: ${successful}`);
|
||
|
console.log(` Total time: ${totalTime}ms`);
|
||
|
console.log(` DNS cache efficiency: ${dnsLookupCount < emails.length ? 'Good' : 'Poor'}`);
|
||
|
console.log(` Expected 1-3 DNS lookups for ${emails.length} emails to same domain`);
|
||
|
|
||
|
smtpClient.close();
|
||
|
} finally {
|
||
|
// Restore original DNS lookup
|
||
|
require('dns').lookup = originalLookup;
|
||
|
testServer.close();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Scenario 2: Multiple Domain DNS Caching
|
||
|
await test.test('Scenario 2: Multiple Domain DNS Caching', async () => {
|
||
|
console.log('\n🌍 Testing DNS caching across multiple domains...');
|
||
|
|
||
|
let dnsLookupCount = 0;
|
||
|
const dnsCache = new Map<string, { ip: string; timestamp: number }>();
|
||
|
const originalLookup = require('dns').lookup;
|
||
|
|
||
|
// Enhanced DNS mock with caching simulation
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
const now = Date.now();
|
||
|
const cached = dnsCache.get(hostname);
|
||
|
|
||
|
if (cached && (now - cached.timestamp) < 3000) { // 3 second cache
|
||
|
console.log(` [DNS] Cache hit for: ${hostname}`);
|
||
|
setTimeout(() => callback(null, cached.ip, 4), 5); // Fast cache response
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
dnsLookupCount++;
|
||
|
console.log(` [DNS] Cache miss, lookup ${dnsLookupCount} for: ${hostname}`);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
const ip = '127.0.0.1';
|
||
|
dnsCache.set(hostname, { ip, timestamp: now });
|
||
|
callback(null, ip, 4);
|
||
|
}, 75); // Slower DNS lookup
|
||
|
};
|
||
|
|
||
|
const testServer = await createTestServer({
|
||
|
responseDelay: 10
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
const smtpClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
pool: true,
|
||
|
maxConnections: 2,
|
||
|
dnsCache: true,
|
||
|
dnsCacheTtl: 3000
|
||
|
});
|
||
|
|
||
|
console.log(' Creating emails to multiple domains...');
|
||
|
const domains = ['domain1.com', 'domain2.com', 'domain3.com'];
|
||
|
const emails = [];
|
||
|
|
||
|
// Create multiple emails per domain
|
||
|
domains.forEach((domain, domainIndex) => {
|
||
|
for (let i = 0; i < 4; i++) {
|
||
|
emails.push(new Email({
|
||
|
from: `sender@${domain}`,
|
||
|
to: [`recipient${i}@${domain}`],
|
||
|
subject: `Multi-domain DNS Test ${domainIndex + 1}-${i + 1}`,
|
||
|
text: `Testing DNS caching for ${domain}`,
|
||
|
messageId: `multi-dns-${domainIndex}-${i}@${domain}`
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
console.log(' Sending emails to test DNS caching across domains...');
|
||
|
const startTime = Date.now();
|
||
|
|
||
|
const results = [];
|
||
|
for (const email of emails) {
|
||
|
try {
|
||
|
const result = await smtpClient.sendMail(email);
|
||
|
results.push({ success: true, result });
|
||
|
console.log(` ✓ Email to ${email.to[0]} sent`);
|
||
|
} catch (error) {
|
||
|
results.push({ success: false, error });
|
||
|
console.log(` ✗ Email to ${email.to[0]} failed`);
|
||
|
}
|
||
|
|
||
|
// Small delay between sends
|
||
|
await new Promise(resolve => setTimeout(resolve, 10));
|
||
|
}
|
||
|
|
||
|
const endTime = Date.now();
|
||
|
const successful = results.filter(r => r.success).length;
|
||
|
|
||
|
console.log(` Total DNS lookups: ${dnsLookupCount}`);
|
||
|
console.log(` Unique domains: ${domains.length}`);
|
||
|
console.log(` Total emails: ${emails.length}, Successful: ${successful}`);
|
||
|
console.log(` Total time: ${endTime - startTime}ms`);
|
||
|
console.log(` DNS cache entries: ${dnsCache.size}`);
|
||
|
console.log(` Expected ~${domains.length} DNS lookups for ${domains.length} domains`);
|
||
|
|
||
|
smtpClient.close();
|
||
|
} finally {
|
||
|
require('dns').lookup = originalLookup;
|
||
|
testServer.close();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Scenario 3: DNS Cache TTL and Refresh
|
||
|
await test.test('Scenario 3: DNS Cache TTL and Refresh', async () => {
|
||
|
console.log('\n⏰ Testing DNS cache TTL and refresh behavior...');
|
||
|
|
||
|
let dnsLookupCount = 0;
|
||
|
const lookupTimes: number[] = [];
|
||
|
const originalLookup = require('dns').lookup;
|
||
|
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
dnsLookupCount++;
|
||
|
const lookupTime = Date.now();
|
||
|
lookupTimes.push(lookupTime);
|
||
|
console.log(` [DNS] Lookup ${dnsLookupCount} at ${new Date(lookupTime).toISOString().substr(11, 12)}`);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
callback(null, '127.0.0.1', 4);
|
||
|
}, 40);
|
||
|
};
|
||
|
|
||
|
const testServer = await createTestServer({
|
||
|
responseDelay: 10
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
const smtpClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
pool: true,
|
||
|
maxConnections: 1,
|
||
|
dnsCache: true,
|
||
|
dnsCacheTtl: 1000 // 1 second TTL for testing
|
||
|
});
|
||
|
|
||
|
console.log(' Sending emails with 1.5 second intervals to test TTL...');
|
||
|
|
||
|
const email1 = new Email({
|
||
|
from: 'sender@ttltest.com',
|
||
|
to: ['recipient1@ttltest.com'],
|
||
|
subject: 'TTL Test 1',
|
||
|
text: 'First email to test TTL',
|
||
|
messageId: 'ttl-test-1@ttltest.com'
|
||
|
});
|
||
|
|
||
|
console.log(' Sending first email...');
|
||
|
await smtpClient.sendMail(email1);
|
||
|
console.log(' ✓ First email sent');
|
||
|
|
||
|
console.log(' Waiting 500ms (within TTL)...');
|
||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||
|
|
||
|
const email2 = new Email({
|
||
|
from: 'sender@ttltest.com',
|
||
|
to: ['recipient2@ttltest.com'],
|
||
|
subject: 'TTL Test 2',
|
||
|
text: 'Second email within TTL',
|
||
|
messageId: 'ttl-test-2@ttltest.com'
|
||
|
});
|
||
|
|
||
|
console.log(' Sending second email (should use cache)...');
|
||
|
await smtpClient.sendMail(email2);
|
||
|
console.log(' ✓ Second email sent');
|
||
|
|
||
|
console.log(' Waiting 1000ms (TTL expiry)...');
|
||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
|
||
|
const email3 = new Email({
|
||
|
from: 'sender@ttltest.com',
|
||
|
to: ['recipient3@ttltest.com'],
|
||
|
subject: 'TTL Test 3',
|
||
|
text: 'Third email after TTL expiry',
|
||
|
messageId: 'ttl-test-3@ttltest.com'
|
||
|
});
|
||
|
|
||
|
console.log(' Sending third email (should trigger new lookup)...');
|
||
|
await smtpClient.sendMail(email3);
|
||
|
console.log(' ✓ Third email sent');
|
||
|
|
||
|
console.log(` Total DNS lookups: ${dnsLookupCount}`);
|
||
|
console.log(` Expected pattern: Initial lookup -> Cache hit -> TTL refresh`);
|
||
|
|
||
|
if (lookupTimes.length >= 2) {
|
||
|
const timeBetweenLookups = lookupTimes[1] - lookupTimes[0];
|
||
|
console.log(` Time between DNS lookups: ${timeBetweenLookups}ms`);
|
||
|
console.log(` TTL behavior: ${timeBetweenLookups > 1000 ? 'Correct' : 'Needs review'}`);
|
||
|
}
|
||
|
|
||
|
smtpClient.close();
|
||
|
} finally {
|
||
|
require('dns').lookup = originalLookup;
|
||
|
testServer.close();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Scenario 4: DNS Cache Memory Management
|
||
|
await test.test('Scenario 4: DNS Cache Memory Management', async () => {
|
||
|
console.log('\n💾 Testing DNS cache memory management and cleanup...');
|
||
|
|
||
|
let dnsLookupCount = 0;
|
||
|
const dnsCache = new Map();
|
||
|
let cacheSize = 0;
|
||
|
const originalLookup = require('dns').lookup;
|
||
|
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
dnsLookupCount++;
|
||
|
|
||
|
if (!dnsCache.has(hostname)) {
|
||
|
dnsCache.set(hostname, {
|
||
|
ip: '127.0.0.1',
|
||
|
timestamp: Date.now(),
|
||
|
hits: 1
|
||
|
});
|
||
|
cacheSize++;
|
||
|
console.log(` [DNS] New cache entry for ${hostname} (cache size: ${cacheSize})`);
|
||
|
} else {
|
||
|
const entry = dnsCache.get(hostname);
|
||
|
entry.hits++;
|
||
|
console.log(` [DNS] Cache hit for ${hostname} (hits: ${entry.hits})`);
|
||
|
}
|
||
|
|
||
|
setTimeout(() => {
|
||
|
callback(null, '127.0.0.1', 4);
|
||
|
}, 30);
|
||
|
};
|
||
|
|
||
|
const testServer = await createTestServer({
|
||
|
responseDelay: 10
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
const smtpClient = createSmtpClient({
|
||
|
host: testServer.hostname,
|
||
|
port: testServer.port,
|
||
|
secure: false,
|
||
|
pool: true,
|
||
|
maxConnections: 2,
|
||
|
dnsCache: true,
|
||
|
dnsCacheTtl: 2000,
|
||
|
dnsCacheSize: 5 // Small cache size for testing
|
||
|
});
|
||
|
|
||
|
console.log(' Creating emails to many domains to test cache limits...');
|
||
|
const domains = [];
|
||
|
for (let i = 0; i < 8; i++) {
|
||
|
domains.push(`domain${i}.example.com`);
|
||
|
}
|
||
|
|
||
|
console.log(' Sending emails to test cache memory management...');
|
||
|
for (let i = 0; i < domains.length; i++) {
|
||
|
const email = new Email({
|
||
|
from: `sender@${domains[i]}`,
|
||
|
to: [`recipient@${domains[i]}`],
|
||
|
subject: `Cache Memory Test ${i + 1}`,
|
||
|
text: `Testing cache for ${domains[i]}`,
|
||
|
messageId: `cache-mem-${i}@${domains[i]}`
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
await smtpClient.sendMail(email);
|
||
|
console.log(` ✓ Email ${i + 1} to ${domains[i]} sent`);
|
||
|
} catch (error) {
|
||
|
console.log(` ✗ Email ${i + 1} failed: ${error.message}`);
|
||
|
}
|
||
|
|
||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||
|
}
|
||
|
|
||
|
console.log(' Testing cache hit rates by resending to same domains...');
|
||
|
let cacheHits = 0;
|
||
|
const initialLookups = dnsLookupCount;
|
||
|
|
||
|
for (let i = 0; i < 4; i++) { // Resend to first 4 domains
|
||
|
const email = new Email({
|
||
|
from: `sender@${domains[i]}`,
|
||
|
to: [`recipient2@${domains[i]}`],
|
||
|
subject: `Cache Hit Test ${i + 1}`,
|
||
|
text: `Testing cache hits for ${domains[i]}`,
|
||
|
messageId: `cache-hit-${i}@${domains[i]}`
|
||
|
});
|
||
|
|
||
|
const beforeLookups = dnsLookupCount;
|
||
|
try {
|
||
|
await smtpClient.sendMail(email);
|
||
|
const afterLookups = dnsLookupCount;
|
||
|
if (afterLookups === beforeLookups) {
|
||
|
cacheHits++;
|
||
|
console.log(` ✓ Cache hit for ${domains[i]}`);
|
||
|
} else {
|
||
|
console.log(` ⚡ Cache miss for ${domains[i]}`);
|
||
|
}
|
||
|
} catch (error) {
|
||
|
console.log(` ✗ Email failed: ${error.message}`);
|
||
|
}
|
||
|
|
||
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||
|
}
|
||
|
|
||
|
const finalLookups = dnsLookupCount;
|
||
|
console.log(` Total DNS lookups: ${finalLookups}`);
|
||
|
console.log(` Unique domains tested: ${domains.length}`);
|
||
|
console.log(` Cache entries created: ${cacheSize}`);
|
||
|
console.log(` Cache hits on retests: ${cacheHits}/4`);
|
||
|
console.log(` Cache efficiency: ${((cacheHits / 4) * 100).toFixed(1)}%`);
|
||
|
console.log(` Memory management: ${cacheSize <= 5 ? 'Within limits' : 'Exceeded limits'}`);
|
||
|
|
||
|
smtpClient.close();
|
||
|
} finally {
|
||
|
require('dns').lookup = originalLookup;
|
||
|
testServer.close();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Scenario 5: DNS Resolution Performance Impact
|
||
|
await test.test('Scenario 5: DNS Resolution Performance Impact', async () => {
|
||
|
console.log('\n⚡ Testing DNS resolution performance impact on email sending...');
|
||
|
|
||
|
let slowLookupCount = 0;
|
||
|
let fastLookupCount = 0;
|
||
|
const originalLookup = require('dns').lookup;
|
||
|
|
||
|
// First test: Slow DNS responses
|
||
|
console.log(' Phase 1: Testing with slow DNS responses (200ms delay)...');
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
slowLookupCount++;
|
||
|
console.log(` [DNS-SLOW] Lookup ${slowLookupCount} for: ${hostname}`);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
callback(null, '127.0.0.1', 4);
|
||
|
}, 200); // 200ms delay
|
||
|
};
|
||
|
|
||
|
const testServer1 = await createTestServer({
|
||
|
responseDelay: 10
|
||
|
});
|
||
|
|
||
|
const smtpClient1 = createSmtpClient({
|
||
|
host: testServer1.hostname,
|
||
|
port: testServer1.port,
|
||
|
secure: false,
|
||
|
pool: false, // No pooling to force DNS lookups
|
||
|
dnsCache: false
|
||
|
});
|
||
|
|
||
|
const emails1 = [];
|
||
|
for (let i = 0; i < 3; i++) {
|
||
|
emails1.push(new Email({
|
||
|
from: 'sender@slow.example.com',
|
||
|
to: [`recipient${i}@slow.example.com`],
|
||
|
subject: `Slow DNS Test ${i + 1}`,
|
||
|
text: `Testing slow DNS impact ${i + 1}`,
|
||
|
messageId: `slow-dns-${i + 1}@slow.example.com`
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
const slowStartTime = Date.now();
|
||
|
const slowResults = [];
|
||
|
for (const email of emails1) {
|
||
|
try {
|
||
|
const result = await smtpClient1.sendMail(email);
|
||
|
slowResults.push({ success: true });
|
||
|
console.log(` ✓ Slow DNS email sent`);
|
||
|
} catch (error) {
|
||
|
slowResults.push({ success: false });
|
||
|
console.log(` ✗ Slow DNS email failed`);
|
||
|
}
|
||
|
}
|
||
|
const slowEndTime = Date.now();
|
||
|
const slowTotalTime = slowEndTime - slowStartTime;
|
||
|
|
||
|
smtpClient1.close();
|
||
|
testServer1.close();
|
||
|
|
||
|
// Second test: Fast DNS responses with caching
|
||
|
console.log(' Phase 2: Testing with fast DNS responses and caching...');
|
||
|
require('dns').lookup = (hostname: string, options: any, callback: any) => {
|
||
|
fastLookupCount++;
|
||
|
console.log(` [DNS-FAST] Lookup ${fastLookupCount} for: ${hostname}`);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
callback(null, '127.0.0.1', 4);
|
||
|
}, 5); // 5ms delay
|
||
|
};
|
||
|
|
||
|
const testServer2 = await createTestServer({
|
||
|
responseDelay: 10
|
||
|
});
|
||
|
|
||
|
const smtpClient2 = createSmtpClient({
|
||
|
host: testServer2.hostname,
|
||
|
port: testServer2.port,
|
||
|
secure: false,
|
||
|
pool: true,
|
||
|
dnsCache: true,
|
||
|
dnsCacheTtl: 5000
|
||
|
});
|
||
|
|
||
|
const emails2 = [];
|
||
|
for (let i = 0; i < 3; i++) {
|
||
|
emails2.push(new Email({
|
||
|
from: 'sender@fast.example.com',
|
||
|
to: [`recipient${i}@fast.example.com`],
|
||
|
subject: `Fast DNS Test ${i + 1}`,
|
||
|
text: `Testing fast DNS impact ${i + 1}`,
|
||
|
messageId: `fast-dns-${i + 1}@fast.example.com`
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
const fastStartTime = Date.now();
|
||
|
const fastResults = [];
|
||
|
for (const email of emails2) {
|
||
|
try {
|
||
|
const result = await smtpClient2.sendMail(email);
|
||
|
fastResults.push({ success: true });
|
||
|
console.log(` ✓ Fast DNS email sent`);
|
||
|
} catch (error) {
|
||
|
fastResults.push({ success: false });
|
||
|
console.log(` ✗ Fast DNS email failed`);
|
||
|
}
|
||
|
}
|
||
|
const fastEndTime = Date.now();
|
||
|
const fastTotalTime = fastEndTime - fastStartTime;
|
||
|
|
||
|
smtpClient2.close();
|
||
|
testServer2.close();
|
||
|
|
||
|
// Performance comparison
|
||
|
const slowSuccess = slowResults.filter(r => r.success).length;
|
||
|
const fastSuccess = fastResults.filter(r => r.success).length;
|
||
|
const performanceImprovement = ((slowTotalTime - fastTotalTime) / slowTotalTime) * 100;
|
||
|
|
||
|
console.log(` Slow DNS Results: ${slowTotalTime}ms, ${slowSuccess}/${emails1.length} successful`);
|
||
|
console.log(` Fast DNS Results: ${fastTotalTime}ms, ${fastSuccess}/${emails2.length} successful`);
|
||
|
console.log(` Performance improvement: ${performanceImprovement.toFixed(1)}%`);
|
||
|
console.log(` DNS lookups - Slow: ${slowLookupCount}, Fast: ${fastLookupCount}`);
|
||
|
console.log(` Caching efficiency: ${fastLookupCount < slowLookupCount ? 'Effective' : 'Needs improvement'}`);
|
||
|
|
||
|
// Restore original DNS lookup
|
||
|
require('dns').lookup = originalLookup;
|
||
|
});
|
||
|
|
||
|
console.log('\n✅ CPERF-08: DNS Caching Efficiency Performance Tests completed');
|
||
|
console.log('🌐 All DNS caching scenarios tested successfully');
|
||
|
});
|