165 lines
4.1 KiB
Go
165 lines
4.1 KiB
Go
// Package proxy 提供 DNS 代理功能的测试。
|
||
//
|
||
// 该文件测试 proxy_dns.go 中的 DNS 相关功能,包括:
|
||
// - DNS 解析器设置和获取
|
||
// - DNS 缓存刷新机制
|
||
// - HostClient 地址更新
|
||
// - 错误处理场景
|
||
//
|
||
// 作者:xfy
|
||
package proxy
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"sync"
|
||
"testing"
|
||
"time"
|
||
|
||
"rua.plus/lolly/internal/config"
|
||
"rua.plus/lolly/internal/loadbalance"
|
||
"rua.plus/lolly/internal/resolver"
|
||
)
|
||
|
||
// mockResolver 实现 resolver.Resolver 接口的模拟解析器。
|
||
type mockResolver struct {
|
||
mu sync.RWMutex
|
||
lookupResults map[string][]string
|
||
lookupError error
|
||
startErr error
|
||
stopErr error
|
||
lookupHostCalls int
|
||
lookupWithCacheCalls int
|
||
startCalls int
|
||
stopCalls int
|
||
}
|
||
|
||
func (m *mockResolver) LookupHost(_ context.Context, host string) ([]string, error) {
|
||
m.mu.Lock()
|
||
m.lookupHostCalls++
|
||
m.mu.Unlock()
|
||
return m.resolve(host)
|
||
}
|
||
|
||
func (m *mockResolver) LookupHostWithCache(_ context.Context, host string) ([]string, error) {
|
||
m.mu.Lock()
|
||
m.lookupWithCacheCalls++
|
||
m.mu.Unlock()
|
||
return m.resolve(host)
|
||
}
|
||
|
||
func (m *mockResolver) resolve(host string) ([]string, error) {
|
||
m.mu.RLock()
|
||
defer m.mu.RUnlock()
|
||
|
||
if m.lookupError != nil {
|
||
return nil, m.lookupError
|
||
}
|
||
if ips, ok := m.lookupResults[host]; ok {
|
||
return ips, nil
|
||
}
|
||
return nil, errors.New("host not found in mock resolver")
|
||
}
|
||
|
||
func (m *mockResolver) Refresh(_ string) error {
|
||
return nil
|
||
}
|
||
|
||
func (m *mockResolver) Start() error {
|
||
m.mu.Lock()
|
||
m.startCalls++
|
||
m.mu.Unlock()
|
||
return m.startErr
|
||
}
|
||
|
||
func (m *mockResolver) Stop() error {
|
||
m.mu.Lock()
|
||
m.stopCalls++
|
||
m.mu.Unlock()
|
||
return m.stopErr
|
||
}
|
||
|
||
func (m *mockResolver) Stats() resolver.Stats {
|
||
m.mu.RLock()
|
||
defer m.mu.RUnlock()
|
||
return resolver.Stats{
|
||
CacheHits: int64(m.lookupWithCacheCalls),
|
||
CacheMisses: int64(m.lookupHostCalls),
|
||
}
|
||
}
|
||
|
||
// TestSetResolver 测试设置 DNS 解析器。
|
||
func TestSetResolver(t *testing.T) {
|
||
cfg := &config.ProxyConfig{
|
||
Path: "/api",
|
||
LoadBalance: "round_robin",
|
||
Timeout: config.ProxyTimeout{Connect: 5 * time.Second},
|
||
}
|
||
targets := []*loadbalance.Target{
|
||
{URL: "http://localhost:8080"},
|
||
}
|
||
|
||
p, err := NewProxy(cfg, targets, nil, nil)
|
||
if err != nil {
|
||
t.Fatalf("NewProxy() error: %v", err)
|
||
}
|
||
|
||
// 初始状态 resolver 为 nil
|
||
if p.resolver != nil {
|
||
t.Error("resolver should be nil initially")
|
||
}
|
||
|
||
// 设置解析器
|
||
mr := &mockResolver{}
|
||
p.SetResolver(mr)
|
||
|
||
if p.resolver != mr {
|
||
t.Error("SetResolver() did not set resolver correctly")
|
||
}
|
||
}
|
||
|
||
// TestGetResolverStats_NoResolver 测试没有解析器时返回空统计。
|
||
|
||
// TestGetResolverStats_WithResolver 测试有解析器时返回统计。
|
||
|
||
// TestStartWithResolver 测试启动代理时解析器正确启动。
|
||
|
||
// TestStartResolverFails 测试解析器启动失败时代理返回错误。
|
||
|
||
// TestStartIdempotent 测试 Start 是幂等的。
|
||
|
||
// TestStopIdempotent 测试 Stop 是幂等的。
|
||
|
||
// TestStopWithoutResolver 测试没有解析器时停止代理。
|
||
|
||
// TestRefreshDNS_Success 测试 DNS 刷新成功场景。
|
||
|
||
// TestRefreshDNS_LookupError 测试 DNS 刷新时查找失败场景。
|
||
|
||
// TestRefreshDNS_NoResolver 测试没有解析器时刷新不执行任何操作。
|
||
|
||
// TestRefreshDNS_IPAddressTarget 测试 IP 类型的目标不需要解析。
|
||
|
||
// TestRefreshDNS_RecentlyResolved 测试最近已解析的目标不需要再次解析。
|
||
|
||
// TestRefreshDNS_ExpiredResolve 测试 TTL 过期后需要重新解析。
|
||
// 该测试验证 TTL 过期检查的正确性:
|
||
// - 短时间内(< TTL)不需要重新解析
|
||
// - 长时间后(> TTL)需要重新解析
|
||
|
||
// TestUpdateHostClientAddr_HTTP 测试 HTTP 目标地址更新。
|
||
|
||
// TestUpdateHostClientAddr_HTTPS 测试 HTTPS 目标地址更新。
|
||
|
||
// TestUpdateHostClientAddr_DefaultPort 测试没有端口时使用默认端口。
|
||
|
||
// TestUpdateHostClientAddr_NonExistentTarget 测试不存在的目标不更新。
|
||
|
||
// TestGetResolverTTL 测试 TTL 获取。
|
||
|
||
// TestDNSRefreshLoop_StartStop 测试 DNS 刷新循环的启动和停止。
|
||
|
||
// TestMultipleTargets_Refresh 测试多目标刷新。
|
||
|
||
// TestStopResolverFails 测试停止解析器失败时返回错误。
|