254 lines
No EOL
7 KiB
TypeScript
254 lines
No EOL
7 KiB
TypeScript
import { beforeEach, describe, expect, it, mock } from 'bun:test';
|
|
import { SimpleProxyManager } from '../src/simple-proxy-manager';
|
|
import type { ProxyConfig, ProxyInfo } from '../src/types';
|
|
|
|
describe('ProxyManager', () => {
|
|
let manager: SimpleProxyManager;
|
|
|
|
const getMockProxies = (): ProxyInfo[] => [
|
|
{
|
|
id: 'proxy1',
|
|
host: '1.2.3.4',
|
|
port: 8080,
|
|
protocol: 'http',
|
|
username: 'user1',
|
|
password: 'pass1',
|
|
active: true,
|
|
},
|
|
{
|
|
id: 'proxy2',
|
|
host: '5.6.7.8',
|
|
port: 8080,
|
|
protocol: 'http',
|
|
username: 'user2',
|
|
password: 'pass2',
|
|
active: true,
|
|
},
|
|
{
|
|
id: 'proxy3',
|
|
host: '9.10.11.12',
|
|
port: 8080,
|
|
protocol: 'socks5',
|
|
active: false,
|
|
},
|
|
];
|
|
|
|
beforeEach(() => {
|
|
manager = new SimpleProxyManager();
|
|
});
|
|
|
|
describe('proxy management', () => {
|
|
it('should add proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
manager.addProxy(mockProxies[1]);
|
|
|
|
const proxies = manager.getProxies();
|
|
expect(proxies).toHaveLength(2);
|
|
expect(proxies[0].id).toBe('proxy1');
|
|
expect(proxies[1].id).toBe('proxy2');
|
|
});
|
|
|
|
it('should remove proxy by id', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
manager.addProxy(mockProxies[1]);
|
|
|
|
manager.removeProxy('proxy1');
|
|
|
|
const proxies = manager.getProxies();
|
|
expect(proxies).toHaveLength(1);
|
|
expect(proxies[0].id).toBe('proxy2');
|
|
});
|
|
|
|
it('should update proxy status', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
|
|
manager.updateProxyStatus('proxy1', false);
|
|
|
|
const proxies = manager.getProxies();
|
|
expect(proxies[0].active).toBe(false);
|
|
});
|
|
|
|
it('should get only active proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
mockProxies.forEach(proxy => manager.addProxy(proxy));
|
|
|
|
const activeProxies = manager.getActiveProxies();
|
|
|
|
expect(activeProxies).toHaveLength(2);
|
|
expect(activeProxies.every(p => p.active)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('proxy rotation', () => {
|
|
it('should rotate through proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
manager.addProxy(mockProxies[1]);
|
|
|
|
const proxy1 = manager.getNextProxy();
|
|
const proxy2 = manager.getNextProxy();
|
|
const proxy3 = manager.getNextProxy();
|
|
|
|
expect(proxy1?.id).toBe('proxy1');
|
|
expect(proxy2?.id).toBe('proxy2');
|
|
expect(proxy3?.id).toBe('proxy1'); // Back to first
|
|
});
|
|
|
|
it('should skip inactive proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
mockProxies.forEach(proxy => manager.addProxy(proxy));
|
|
|
|
const proxy1 = manager.getNextProxy();
|
|
const proxy2 = manager.getNextProxy();
|
|
const proxy3 = manager.getNextProxy();
|
|
|
|
expect(proxy1?.id).toBe('proxy1');
|
|
expect(proxy2?.id).toBe('proxy2');
|
|
expect(proxy3?.id).toBe('proxy1'); // Skips proxy3 (inactive)
|
|
});
|
|
|
|
it('should return null when no active proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy({ ...mockProxies[0], active: false });
|
|
|
|
const proxy = manager.getNextProxy();
|
|
|
|
expect(proxy).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('proxy configuration', () => {
|
|
it('should get proxy config for HTTP proxy', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
const proxy = manager.getNextProxy();
|
|
|
|
const config = manager.getProxyConfig(proxy!);
|
|
|
|
expect(config).toEqual({
|
|
protocol: 'http',
|
|
host: '1.2.3.4',
|
|
port: 8080,
|
|
auth: {
|
|
username: 'user1',
|
|
password: 'pass1',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should get proxy config without auth', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[2]);
|
|
manager.updateProxyStatus('proxy3', true); // Make it active
|
|
const proxy = manager.getNextProxy();
|
|
|
|
const config = manager.getProxyConfig(proxy!);
|
|
|
|
expect(config).toEqual({
|
|
protocol: 'socks5',
|
|
host: '9.10.11.12',
|
|
port: 8080,
|
|
});
|
|
});
|
|
|
|
it('should format proxy URL', () => {
|
|
const mockProxies = getMockProxies();
|
|
const url1 = manager.formatProxyUrl(mockProxies[0]);
|
|
expect(url1).toBe('http://user1:pass1@1.2.3.4:8080');
|
|
|
|
const url2 = manager.formatProxyUrl(mockProxies[2]);
|
|
expect(url2).toBe('socks5://9.10.11.12:8080');
|
|
});
|
|
});
|
|
|
|
describe('proxy validation', () => {
|
|
it('should validate proxy connectivity', async () => {
|
|
const mockProxies = getMockProxies();
|
|
// Mock fetch for validation
|
|
const mockFetch = mock(() => Promise.resolve({ ok: true }));
|
|
global.fetch = mockFetch as any;
|
|
|
|
manager.addProxy(mockProxies[0]);
|
|
|
|
const isValid = await manager.validateProxy('proxy1');
|
|
|
|
expect(mockFetch).toHaveBeenCalled();
|
|
expect(isValid).toBe(true);
|
|
});
|
|
|
|
it('should handle validation failure', async () => {
|
|
const mockProxies = getMockProxies();
|
|
const mockFetch = mock(() => Promise.reject(new Error('Connection failed')));
|
|
global.fetch = mockFetch as any;
|
|
|
|
manager.addProxy(mockProxies[0]);
|
|
|
|
const isValid = await manager.validateProxy('proxy1');
|
|
|
|
expect(isValid).toBe(false);
|
|
});
|
|
|
|
it('should validate all proxies', async () => {
|
|
const mockProxies = getMockProxies();
|
|
|
|
// Mock fetch to return different results for each proxy
|
|
let callCount = 0;
|
|
const mockFetch = mock(() => {
|
|
callCount++;
|
|
// First call succeeds, second fails
|
|
if (callCount === 1) {
|
|
return Promise.resolve({ ok: true });
|
|
} else {
|
|
return Promise.reject(new Error('Failed'));
|
|
}
|
|
});
|
|
global.fetch = mockFetch as any;
|
|
|
|
manager.addProxy(mockProxies[0]);
|
|
manager.addProxy(mockProxies[1]);
|
|
|
|
const results = await manager.validateAllProxies();
|
|
|
|
expect(results['proxy1']).toBe(true);
|
|
expect(results['proxy2']).toBe(false);
|
|
|
|
// Should disable failed proxy
|
|
const activeProxies = manager.getActiveProxies();
|
|
expect(activeProxies).toHaveLength(1);
|
|
expect(activeProxies[0].id).toBe('proxy1');
|
|
});
|
|
});
|
|
|
|
describe('statistics', () => {
|
|
it('should track proxy statistics', () => {
|
|
const mockProxies = getMockProxies();
|
|
mockProxies.forEach(proxy => manager.addProxy(proxy));
|
|
|
|
const stats = manager.getStatistics();
|
|
|
|
expect(stats).toEqual({
|
|
total: 3,
|
|
active: 2,
|
|
inactive: 1,
|
|
byProtocol: {
|
|
http: 2,
|
|
socks5: 1,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should clear all proxies', () => {
|
|
const mockProxies = getMockProxies();
|
|
manager.addProxy(mockProxies[0]);
|
|
manager.addProxy(mockProxies[1]);
|
|
|
|
manager.clear();
|
|
|
|
const proxies = manager.getProxies();
|
|
expect(proxies).toHaveLength(0);
|
|
});
|
|
});
|
|
}); |