import { tap, expect } from '@push.rocks/tapbundle'; import * as plugins from '../ts/plugins.js'; import * as paths from '../ts/paths.js'; import { IPWarmupManager } from '../ts/deliverability/classes.ipwarmupmanager.js'; // Cleanup any temporary test data const cleanupTestData = () => { const warmupDataPath = plugins.path.join(paths.dataDir, 'warmup'); if (plugins.fs.existsSync(warmupDataPath)) { plugins.smartfile.memory.unlinkDir(warmupDataPath); } }; // Helper to reset the singleton instance between tests const resetSingleton = () => { // @ts-ignore - accessing private static field for testing IPWarmupManager._instance = null; }; // Before running any tests tap.test('setup', async () => { cleanupTestData(); }); // Test initialization of IPWarmupManager tap.test('should initialize IPWarmupManager with default settings', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance(); expect(ipWarmupManager).to.be.an('object'); expect(ipWarmupManager.getBestIPForSending).to.be.a('function'); expect(ipWarmupManager.canSendMoreToday).to.be.a('function'); expect(ipWarmupManager.getStageCount).to.be.a('function'); expect(ipWarmupManager.setActiveAllocationPolicy).to.be.a('function'); }); // Test initialization with custom settings tap.test('should initialize IPWarmupManager with custom settings', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2'], targetDomains: ['example.com', 'test.com'], fallbackPercentage: 75 }); // Test setting allocation policy ipWarmupManager.setActiveAllocationPolicy('roundRobin'); // Get best IP for sending const bestIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); // Check if we can send more today const canSendMore = ipWarmupManager.canSendMoreToday('192.168.1.1'); // Check stage count const stageCount = ipWarmupManager.getStageCount(); expect(stageCount).to.be.a('number'); }); // Test IP allocation policies tap.test('should allocate IPs using balanced policy', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2', '192.168.1.3'], targetDomains: ['example.com', 'test.com'], allocationPolicy: 'balanced' }); ipWarmupManager.setActiveAllocationPolicy('balanced'); // Use getBestIPForSending multiple times and check if all IPs are used const usedIPs = new Set(); for (let i = 0; i < 30; i++) { const ip = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); if (ip) usedIPs.add(ip); } // We should use at least 2 different IPs with balanced policy expect(usedIPs.size).to.be.at.least(2); }); // Test round robin allocation policy tap.test('should allocate IPs using round robin policy', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2', '192.168.1.3'], targetDomains: ['example.com', 'test.com'], allocationPolicy: 'roundRobin' }); ipWarmupManager.setActiveAllocationPolicy('roundRobin'); // First few IPs should rotate through the available IPs const firstIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); const secondIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); const thirdIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); // Round robin should give us different IPs for consecutive calls expect(firstIP).to.not.equal(secondIP); // Fourth call should cycle back to first IP const fourthIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); expect(fourthIP).to.equal(firstIP); }); // Test dedicated domain allocation policy tap.test('should allocate IPs using dedicated domain policy', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2', '192.168.1.3'], targetDomains: ['example.com', 'test.com', 'other.com'], allocationPolicy: 'dedicatedDomain' }); ipWarmupManager.setActiveAllocationPolicy('dedicatedDomain'); // Map domains to IPs ipWarmupManager.mapDomainToIP('example.com', '192.168.1.1'); ipWarmupManager.mapDomainToIP('test.com', '192.168.1.2'); ipWarmupManager.mapDomainToIP('other.com', '192.168.1.3'); // Each domain should get its dedicated IP const exampleIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@gmail.com'], domain: 'example.com' }); const testIP = ipWarmupManager.getBestIPForSending({ from: 'test@test.com', to: ['recipient@gmail.com'], domain: 'test.com' }); const otherIP = ipWarmupManager.getBestIPForSending({ from: 'test@other.com', to: ['recipient@gmail.com'], domain: 'other.com' }); expect(exampleIP).to.equal('192.168.1.1'); expect(testIP).to.equal('192.168.1.2'); expect(otherIP).to.equal('192.168.1.3'); }); // Test daily sending limits tap.test('should enforce daily sending limits', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1'], targetDomains: ['example.com'], allocationPolicy: 'balanced' }); // Override the warmup stage for testing // @ts-ignore - accessing private method for testing ipWarmupManager.warmupStatus.set('192.168.1.1', { isActive: true, currentStage: 0, startDate: new Date(), dailySendCount: 0, hourlySendCount: {} }); // Set a very low daily limit for testing // @ts-ignore - accessing private method for testing ipWarmupManager.warmupStages = [ { dailyLimit: 5, duration: 5, hourlyPercentage: { min: 0, max: 40 } } ]; // First 5 sends should succeed for (let i = 0; i < 5; i++) { const ip = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); expect(ip).to.equal('192.168.1.1'); ipWarmupManager.recordSend(ip); } // 6th send should not get an IP due to daily limit const sixthIP = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); expect(sixthIP).to.be.null; }); // Test recording sends tap.test('should record send events correctly', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2'], targetDomains: ['example.com'], }); // Set allocation policy ipWarmupManager.setActiveAllocationPolicy('balanced'); // Get an IP for sending const ip = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); // If we got an IP, record some sends if (ip) { // Record a few sends for (let i = 0; i < 5; i++) { ipWarmupManager.recordSend(ip); } // Check if we can still send more const canSendMore = ipWarmupManager.canSendMoreToday(ip); expect(canSendMore).to.be.a('boolean'); } }); // Test that DedicatedDomainPolicy assigns IPs correctly tap.test('should assign IPs using dedicated domain policy', async () => { resetSingleton(); const ipWarmupManager = IPWarmupManager.getInstance({ enabled: true, ipAddresses: ['192.168.1.1', '192.168.1.2', '192.168.1.3'], targetDomains: ['example.com', 'test.com', 'other.com'] }); // Set allocation policy to dedicated domains ipWarmupManager.setActiveAllocationPolicy('dedicated'); // Check allocation by querying for different domains const ip1 = ipWarmupManager.getBestIPForSending({ from: 'test@example.com', to: ['recipient@test.com'], domain: 'example.com' }); const ip2 = ipWarmupManager.getBestIPForSending({ from: 'test@test.com', to: ['recipient@test.com'], domain: 'test.com' }); // If we got IPs, they should be consistently assigned if (ip1 && ip2) { // Requesting the same domain again should return the same IP const ip1again = ipWarmupManager.getBestIPForSending({ from: 'another@example.com', to: ['recipient@test.com'], domain: 'example.com' }); expect(ip1again).to.equal(ip1); } }); // After all tests, clean up tap.test('cleanup', async () => { cleanupTestData(); }); export default tap.start();