test(integration): 添加缓存和代理集成测试
- cache_integration_test.go: 缓存创建、存取、过期、stale、并发测试 - proxy_integration_test.go: 代理创建、负载均衡、超时、健康检查测试 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
ad88770472
commit
604bc719f9
275
internal/integration/cache_integration_test.go
Normal file
275
internal/integration/cache_integration_test.go
Normal file
@ -0,0 +1,275 @@
|
||||
//go:build integration
|
||||
|
||||
// cache_integration_test.go - 缓存集成测试(L2 层,进程内)
|
||||
//
|
||||
// 测试代理缓存的核心功能。
|
||||
//
|
||||
// 作者:xfy
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"rua.plus/lolly/internal/cache"
|
||||
)
|
||||
|
||||
// TestProxyCacheCreation 测试代理缓存创建
|
||||
func TestProxyCacheCreation(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/api/",
|
||||
Methods: []string{"GET", "HEAD"},
|
||||
Statuses: []int{200, 301, 302},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
}
|
||||
|
||||
// TestProxyCacheDisabled 测试禁用缓存(空规则)
|
||||
func TestProxyCacheDisabled(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{}
|
||||
|
||||
pc := cache.NewProxyCache(rules, false, 0)
|
||||
require.NotNil(t, pc)
|
||||
}
|
||||
|
||||
// TestProxyCacheSetAndGet 测试缓存存取
|
||||
func TestProxyCacheSetAndGet(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
origKey := "GET:/test"
|
||||
hashKey := cache.HashPathWithMethod("/test", "GET")
|
||||
body := []byte("test response body")
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
"X-Custom": "value",
|
||||
}
|
||||
|
||||
// 存入缓存
|
||||
pc.Set(hashKey, origKey, body, headers, 200, 60*time.Second)
|
||||
|
||||
// 从缓存获取
|
||||
entry, found, stale := pc.Get(hashKey, origKey)
|
||||
assert.True(t, found)
|
||||
assert.False(t, stale)
|
||||
require.NotNil(t, entry)
|
||||
assert.Equal(t, 200, entry.Status)
|
||||
assert.Equal(t, body, entry.Data)
|
||||
assert.Equal(t, "application/json", entry.Headers["Content-Type"])
|
||||
}
|
||||
|
||||
// TestProxyCacheMiss 测试缓存未命中
|
||||
func TestProxyCacheMiss(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
origKey := "GET:/nonexistent"
|
||||
hashKey := cache.HashPathWithMethod("/nonexistent", "GET")
|
||||
|
||||
// 不存在的键应返回未命中
|
||||
entry, found, stale := pc.Get(hashKey, origKey)
|
||||
assert.False(t, found)
|
||||
assert.False(t, stale)
|
||||
assert.Nil(t, entry)
|
||||
}
|
||||
|
||||
// TestProxyCacheExpiration 测试缓存过期
|
||||
func TestProxyCacheExpiration(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 100 * time.Millisecond, // 短过期时间
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 50*time.Millisecond)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
origKey := "GET:/expiring"
|
||||
hashKey := cache.HashPathWithMethod("/expiring", "GET")
|
||||
body := []byte("will expire")
|
||||
|
||||
// 存入缓存
|
||||
pc.Set(hashKey, origKey, body, nil, 200, 100*time.Millisecond)
|
||||
|
||||
// 立即获取应该命中
|
||||
entry, found, _ := pc.Get(hashKey, origKey)
|
||||
assert.True(t, found)
|
||||
assert.NotNil(t, entry)
|
||||
|
||||
// 等待过期
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
// 过期后应该未命中
|
||||
entry, found, stale := pc.Get(hashKey, origKey)
|
||||
assert.False(t, found)
|
||||
assert.False(t, stale)
|
||||
assert.Nil(t, entry)
|
||||
}
|
||||
|
||||
// TestProxyCacheStale 测试过期缓存复用
|
||||
func TestProxyCacheStale(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 100 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
// staleTime = 200ms,允许过期后 200ms 内复用
|
||||
pc := cache.NewProxyCache(rules, true, 200*time.Millisecond)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
origKey := "GET:/stale"
|
||||
hashKey := cache.HashPathWithMethod("/stale", "GET")
|
||||
body := []byte("stale data")
|
||||
|
||||
// 存入缓存
|
||||
pc.Set(hashKey, origKey, body, nil, 200, 100*time.Millisecond)
|
||||
|
||||
// 等待过期但仍在 stale 时间内
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
|
||||
// 应该返回 stale 数据
|
||||
entry, found, stale := pc.Get(hashKey, origKey)
|
||||
assert.True(t, found)
|
||||
assert.True(t, stale)
|
||||
assert.NotNil(t, entry)
|
||||
assert.Equal(t, body, entry.Data)
|
||||
}
|
||||
|
||||
// TestProxyCacheHashKeyCollision 测试哈希碰撞检测
|
||||
func TestProxyCacheHashKeyCollision(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
// 两个不同的 key
|
||||
key1 := "GET:/resource/1"
|
||||
key2 := "GET:/resource/2"
|
||||
|
||||
hashKey1 := cache.HashPathWithMethod("/resource/1", "GET")
|
||||
hashKey2 := cache.HashPathWithMethod("/resource/2", "GET")
|
||||
|
||||
// 存入不同的数据
|
||||
pc.Set(hashKey1, key1, []byte("data1"), nil, 200, 60*time.Second)
|
||||
pc.Set(hashKey2, key2, []byte("data2"), nil, 200, 60*time.Second)
|
||||
|
||||
// 验证各自返回正确的数据
|
||||
entry1, found1, _ := pc.Get(hashKey1, key1)
|
||||
assert.True(t, found1)
|
||||
assert.Equal(t, []byte("data1"), entry1.Data)
|
||||
|
||||
entry2, found2, _ := pc.Get(hashKey2, key2)
|
||||
assert.True(t, found2)
|
||||
assert.Equal(t, []byte("data2"), entry2.Data)
|
||||
}
|
||||
|
||||
// TestProxyCacheConcurrent 测试并发访问
|
||||
func TestProxyCacheConcurrent(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
// 并发写入
|
||||
done := make(chan bool, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func(idx int) {
|
||||
key := "GET:/concurrent"
|
||||
hashKey := cache.HashPathWithMethod("/concurrent", "GET")
|
||||
pc.Set(hashKey, key, []byte("concurrent data"), nil, 200, 60*time.Second)
|
||||
done <- true
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 等待所有写入完成
|
||||
for i := 0; i < 10; i++ {
|
||||
<-done
|
||||
}
|
||||
|
||||
// 验证数据一致性
|
||||
key := "GET:/concurrent"
|
||||
hashKey := cache.HashPathWithMethod("/concurrent", "GET")
|
||||
entry, found, _ := pc.Get(hashKey, key)
|
||||
assert.True(t, found)
|
||||
assert.NotNil(t, entry)
|
||||
}
|
||||
|
||||
// TestProxyCacheUsesCount 测试访问计数
|
||||
func TestProxyCacheUsesCount(t *testing.T) {
|
||||
rules := []cache.ProxyCacheRule{
|
||||
{
|
||||
Path: "/",
|
||||
Methods: []string{"GET"},
|
||||
Statuses: []int{200},
|
||||
MaxAge: 60 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
pc := cache.NewProxyCache(rules, true, 30*time.Second)
|
||||
require.NotNil(t, pc)
|
||||
|
||||
origKey := "GET:/counted"
|
||||
hashKey := cache.HashPathWithMethod("/counted", "GET")
|
||||
|
||||
// 存入缓存
|
||||
pc.Set(hashKey, origKey, []byte("data"), nil, 200, 60*time.Second)
|
||||
|
||||
// 多次访问
|
||||
for i := 0; i < 5; i++ {
|
||||
entry, found, _ := pc.Get(hashKey, origKey)
|
||||
assert.True(t, found)
|
||||
require.NotNil(t, entry)
|
||||
}
|
||||
|
||||
// 验证访问计数
|
||||
entry, _, _ := pc.Get(hashKey, origKey)
|
||||
require.NotNil(t, entry)
|
||||
// Uses 计数应该是 6(5次循环 + 1次验证)
|
||||
assert.GreaterOrEqual(t, entry.Uses.Load(), int32(6))
|
||||
}
|
||||
404
internal/integration/proxy_integration_test.go
Normal file
404
internal/integration/proxy_integration_test.go
Normal file
@ -0,0 +1,404 @@
|
||||
//go:build integration
|
||||
|
||||
// proxy_integration_test.go - 代理集成测试(L2 层,进程内)
|
||||
//
|
||||
// 测试反向代理的配置和创建逻辑。
|
||||
// 实际的网络转发测试在 L3 E2E 测试中进行。
|
||||
//
|
||||
// 作者:xfy
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"rua.plus/lolly/internal/config"
|
||||
"rua.plus/lolly/internal/loadbalance"
|
||||
"rua.plus/lolly/internal/proxy"
|
||||
)
|
||||
|
||||
// TestProxyCreation 测试代理创建
|
||||
func TestProxyCreation(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
Write: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{
|
||||
URL: "http://127.0.0.1:8081",
|
||||
Weight: 1,
|
||||
MaxFails: 3,
|
||||
},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err, "failed to create proxy")
|
||||
require.NotNil(t, p)
|
||||
|
||||
// 验证配置
|
||||
assert.Equal(t, "round_robin", cfg.LoadBalance)
|
||||
assert.Equal(t, 5*time.Second, cfg.Timeout.Connect)
|
||||
assert.Equal(t, 10*time.Second, cfg.Timeout.Read)
|
||||
}
|
||||
|
||||
// TestProxyRequestHeaders 测试请求头修改配置
|
||||
func TestProxyRequestHeaders(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Headers: config.ProxyHeaders{
|
||||
SetRequest: map[string]string{
|
||||
"X-Custom-Header": "custom-value",
|
||||
"X-Forwarded-Proto": "https",
|
||||
},
|
||||
},
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证代理配置已设置
|
||||
assert.NotNil(t, cfg.Headers.SetRequest)
|
||||
assert.Equal(t, "custom-value", cfg.Headers.SetRequest["X-Custom-Header"])
|
||||
assert.Equal(t, "https", cfg.Headers.SetRequest["X-Forwarded-Proto"])
|
||||
}
|
||||
|
||||
// TestProxyResponseHeaders 测试响应头修改配置
|
||||
func TestProxyResponseHeaders(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Headers: config.ProxyHeaders{
|
||||
SetResponse: map[string]string{
|
||||
"X-Server": "lolly",
|
||||
},
|
||||
Remove: []string{"X-Powered-By"},
|
||||
},
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证响应头配置
|
||||
assert.Equal(t, "lolly", cfg.Headers.SetResponse["X-Server"])
|
||||
assert.Contains(t, cfg.Headers.Remove, "X-Powered-By")
|
||||
}
|
||||
|
||||
// TestProxyTimeout 测试代理超时配置
|
||||
func TestProxyTimeout(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 1 * time.Second,
|
||||
Read: 50 * time.Millisecond,
|
||||
Write: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证超时配置
|
||||
assert.Equal(t, 1*time.Second, cfg.Timeout.Connect)
|
||||
assert.Equal(t, 50*time.Millisecond, cfg.Timeout.Read)
|
||||
assert.Equal(t, 1*time.Second, cfg.Timeout.Write)
|
||||
}
|
||||
|
||||
// TestProxyLoadBalanceRoundRobin 测试轮询负载均衡配置
|
||||
func TestProxyLoadBalanceRoundRobin(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证负载均衡器类型
|
||||
assert.Equal(t, "round_robin", cfg.LoadBalance)
|
||||
assert.Len(t, targets, 2)
|
||||
}
|
||||
|
||||
// TestProxyWeightedRoundRobin 测试加权轮询配置
|
||||
func TestProxyWeightedRoundRobin(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "weighted_round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 3},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证权重配置
|
||||
assert.Equal(t, 3, targets[0].Weight)
|
||||
assert.Equal(t, 1, targets[1].Weight)
|
||||
}
|
||||
|
||||
// TestProxyLeastConn 测试最少连接负载均衡配置
|
||||
func TestProxyLeastConn(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "least_conn",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
assert.Equal(t, "least_conn", cfg.LoadBalance)
|
||||
}
|
||||
|
||||
// TestProxyIPHash 测试 IP 哈希负载均衡配置
|
||||
func TestProxyIPHash(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "ip_hash",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
assert.Equal(t, "ip_hash", cfg.LoadBalance)
|
||||
}
|
||||
|
||||
// TestProxyConsistentHash 测试一致性哈希负载均衡配置
|
||||
func TestProxyConsistentHash(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "consistent_hash",
|
||||
HashKey: "uri",
|
||||
VirtualNodes: 150,
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
assert.Equal(t, "consistent_hash", cfg.LoadBalance)
|
||||
assert.Equal(t, "uri", cfg.HashKey)
|
||||
assert.Equal(t, 150, cfg.VirtualNodes)
|
||||
}
|
||||
|
||||
// TestProxyErrorHandling 测试错误处理配置
|
||||
func TestProxyErrorHandling(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{
|
||||
URL: "http://127.0.0.1:8081",
|
||||
Weight: 1,
|
||||
MaxFails: 3,
|
||||
FailTimeout: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证 MaxFails 配置 (int64 类型)
|
||||
assert.Equal(t, int64(3), targets[0].MaxFails)
|
||||
assert.Equal(t, 10*time.Second, targets[0].FailTimeout)
|
||||
}
|
||||
|
||||
// TestProxyCacheConfig 测试缓存配置
|
||||
func TestProxyCacheConfig(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
Cache: config.ProxyCacheConfig{
|
||||
Enabled: true,
|
||||
MaxAge: 60 * time.Second,
|
||||
Methods: []string{"GET", "HEAD"},
|
||||
MinUses: 1,
|
||||
CacheLock: true,
|
||||
CacheLockTimeout: 5 * time.Second,
|
||||
StaleWhileRevalidate: 30 * time.Second,
|
||||
},
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证缓存配置
|
||||
assert.True(t, cfg.Cache.Enabled)
|
||||
assert.Equal(t, 60*time.Second, cfg.Cache.MaxAge)
|
||||
assert.Contains(t, cfg.Cache.Methods, "GET")
|
||||
assert.True(t, cfg.Cache.CacheLock)
|
||||
}
|
||||
|
||||
// TestProxyNextUpstream 测试故障转移配置
|
||||
func TestProxyNextUpstream(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
NextUpstream: config.NextUpstreamConfig{
|
||||
Tries: 3,
|
||||
HTTPCodes: []int{502, 503, 504},
|
||||
},
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
{URL: "http://127.0.0.1:8082", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证故障转移配置
|
||||
assert.Equal(t, 3, cfg.NextUpstream.Tries)
|
||||
assert.Contains(t, cfg.NextUpstream.HTTPCodes, 502)
|
||||
assert.Contains(t, cfg.NextUpstream.HTTPCodes, 503)
|
||||
assert.Contains(t, cfg.NextUpstream.HTTPCodes, 504)
|
||||
}
|
||||
|
||||
// TestProxyHealthCheck 测试健康检查配置
|
||||
func TestProxyHealthCheck(t *testing.T) {
|
||||
cfg := &config.ProxyConfig{
|
||||
LoadBalance: "round_robin",
|
||||
HealthCheck: config.HealthCheckConfig{
|
||||
Interval: 10 * time.Second,
|
||||
Path: "/health",
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
targets := []*loadbalance.Target{
|
||||
{URL: "http://127.0.0.1:8081", Weight: 1},
|
||||
}
|
||||
|
||||
p, err := proxy.NewProxy(cfg, targets, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = p.Start()
|
||||
require.NoError(t, err)
|
||||
defer p.Stop()
|
||||
|
||||
// 验证健康检查配置
|
||||
assert.Equal(t, 10*time.Second, cfg.HealthCheck.Interval)
|
||||
assert.Equal(t, "/health", cfg.HealthCheck.Path)
|
||||
assert.Equal(t, 5*time.Second, cfg.HealthCheck.Timeout)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user