lolly/internal/proxy/proxy_dns_test.go

165 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 测试停止解析器失败时返回错误。