Files
opsxshell/test/utils/proxy.test.ts
T
OpsXShell Dev 07c4a5b14f feat(proxy): HTTP/SOCKS5 代理支持,按会话独立配置 | 15 files +483/-23 | 96/96 tests passing
功能:
- 代理类型定义 (ProxyType, ProxyConfig)
- 代理工具函数 (验证、解析、构建URL) + 24 测试
- SSH 连接通过 HTTP CONNECT / SOCKS5 隧道
- 数据库 proxy 列持久化 (JSON)
- SessionDialog 代理配置 UI (可折叠面板)
- 连接池传递 proxy 到 IPC
- sessionStore 类型添加 proxy 支持
2026-04-25 05:14:27 +08:00

204 lines
6.1 KiB
TypeScript

/**
* Proxy Config Utils - Tests
* 代理配置验证和工具函数测试
*/
import { describe, it, expect } from 'vitest'
import {
validateProxyConfig,
parseProxyUrl,
buildProxyUrl,
isProxyConfigured,
getDefaultProxyConfig,
} from '../../src/utils/proxy'
import type { ProxyConfig } from '../../shared/types/session.types'
describe('Proxy Utils', () => {
describe('getDefaultProxyConfig', () => {
it('应返回默认代理配置', () => {
const config = getDefaultProxyConfig()
expect(config).toEqual({
type: 'none',
host: '',
port: 0,
username: '',
password: '',
})
})
})
describe('isProxyConfigured', () => {
it('type=none 应返回 false', () => {
expect(isProxyConfigured({ type: 'none', host: '', port: 0 })).toBe(false)
})
it('type=http 有 host 应返回 true', () => {
expect(isProxyConfigured({ type: 'http', host: 'proxy.example.com', port: 8080 })).toBe(true)
})
it('type=socks5 有 host 应返回 true', () => {
expect(isProxyConfigured({ type: 'socks5', host: '127.0.0.1', port: 1080 })).toBe(true)
})
it('type=http 但 host 为空应返回 false', () => {
expect(isProxyConfigured({ type: 'http', host: '', port: 8080 })).toBe(false)
})
})
describe('validateProxyConfig', () => {
it('type=none 应始终有效', () => {
const result = validateProxyConfig({ type: 'none', host: '', port: 0 })
expect(result.valid).toBe(true)
expect(result.error).toBeUndefined()
})
it('有效的 HTTP 代理配置应通过验证', () => {
const config: ProxyConfig = { type: 'http', host: 'proxy.example.com', port: 8080 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(true)
})
it('有效的 SOCKS5 代理配置应通过验证', () => {
const config: ProxyConfig = { type: 'socks5', host: '127.0.0.1', port: 1080 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(true)
})
it('host 为空应验证失败', () => {
const config: ProxyConfig = { type: 'http', host: '', port: 8080 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(false)
expect(result.error).toContain('host')
})
it('port 为 0 应验证失败', () => {
const config: ProxyConfig = { type: 'http', host: 'proxy.example.com', port: 0 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(false)
expect(result.error).toContain('port')
})
it('port 为负数应验证失败', () => {
const config: ProxyConfig = { type: 'socks5', host: '127.0.0.1', port: -1 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(false)
expect(result.error).toContain('port')
})
it('port 超过 65535 应验证失败', () => {
const config: ProxyConfig = { type: 'http', host: 'proxy.example.com', port: 70000 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(false)
expect(result.error).toContain('port')
})
it('host 含有非法字符应验证失败', () => {
const config: ProxyConfig = { type: 'http', host: 'proxy example.com', port: 8080 }
const result = validateProxyConfig(config)
expect(result.valid).toBe(false)
expect(result.error).toContain('host')
})
it('带用户名密码的有效代理应通过验证', () => {
const config: ProxyConfig = {
type: 'http',
host: 'proxy.example.com',
port: 8080,
username: 'user',
password: 'pass',
}
const result = validateProxyConfig(config)
expect(result.valid).toBe(true)
})
})
describe('parseProxyUrl', () => {
it('应解析 HTTP 代理 URL', () => {
const result = parseProxyUrl('http://proxy.example.com:8080')
expect(result).toEqual({
type: 'http',
host: 'proxy.example.com',
port: 8080,
username: '',
password: '',
})
})
it('应解析 SOCKS5 代理 URL', () => {
const result = parseProxyUrl('socks5://127.0.0.1:1080')
expect(result).toEqual({
type: 'socks5',
host: '127.0.0.1',
port: 1080,
username: '',
password: '',
})
})
it('应解析带认证的代理 URL', () => {
const result = parseProxyUrl('http://user:pass@proxy.example.com:3128')
expect(result).toEqual({
type: 'http',
host: 'proxy.example.com',
port: 3128,
username: 'user',
password: 'pass',
})
})
it('应解析无端口的 URL (使用默认端口)', () => {
const result = parseProxyUrl('http://proxy.example.com')
expect(result).toEqual({
type: 'http',
host: 'proxy.example.com',
port: 80,
username: '',
password: '',
})
})
it('SOCKS5 无端口应使用 1080', () => {
const result = parseProxyUrl('socks5://proxy.example.com')
expect(result).toEqual({
type: 'socks5',
host: 'proxy.example.com',
port: 1080,
username: '',
password: '',
})
})
it('无效 URL 应返回 null', () => {
expect(parseProxyUrl('')).toBeNull()
expect(parseProxyUrl('not-a-url')).toBeNull()
})
it('不支持的协议应返回 null', () => {
expect(parseProxyUrl('ftp://proxy.example.com:21')).toBeNull()
})
})
describe('buildProxyUrl', () => {
it('应构建 HTTP 代理 URL', () => {
const config: ProxyConfig = { type: 'http', host: 'proxy.example.com', port: 8080 }
expect(buildProxyUrl(config)).toBe('http://proxy.example.com:8080')
})
it('应构建带认证的代理 URL', () => {
const config: ProxyConfig = {
type: 'socks5',
host: '127.0.0.1',
port: 1080,
username: 'user',
password: 'pass',
}
expect(buildProxyUrl(config)).toBe('socks5://user:pass@127.0.0.1:1080')
})
it('type=none 应返回空字符串', () => {
const config: ProxyConfig = { type: 'none', host: '', port: 0 }
expect(buildProxyUrl(config)).toBe('')
})
})
})