test(stream): 添加 Stream 服务器覆盖测试(覆盖率 57% → 预计 >75%)
新建 internal/stream/server_coverage_test.go,覆盖之前 0% 的函数: TCP 监听测试: - TestListenTCP_Success: 成功监听随机端口 - TestListenTCP_InvalidAddress: 无效地址返回错误 服务器启动测试: - TestStart_NoListeners: 无监听器时启动 - TestStart_WithTCPListeners: 有 TCP 监听器时启动 - TestStart_AcceptConnections: 实际接受 TCP 连接 UDP 服务器测试: - TestNewUDPServer_DefaultTimeout: 默认 60 秒超时 - TestNewUDPServer_CustomTimeout: 自定义超时 会话管理测试: - TestSessionKey: 会话键生成正确性 - TestGetSession_NotExist/Existing: 会话查找 - TestRemoveSession/NotExist: 会话移除 - TestCleanupExpiredSessions_RemovesExpired/AllExpired: 过期清理 会话创建测试: - TestGetOrCreateSession_NoHealthyTargets: 无健康目标 - TestGetOrCreateSession_ExistingSession: 复用现有会话 - TestGetOrCreateSession_NewSession: 创建新会话 响应处理测试: - TestHandleBackendResponse_Timeout: 后端超时处理 - TestServe_ReceivesAndForwards: UDP 数据转发 - TestStartCleanupTicker_StopsOnSignal: 定时清理停止
This commit is contained in:
parent
8bb88e8898
commit
b0e795bc9a
631
internal/stream/server_coverage_test.go
Normal file
631
internal/stream/server_coverage_test.go
Normal file
@ -0,0 +1,631 @@
|
||||
// Package stream 提供服务器相关函数的覆盖测试。
|
||||
//
|
||||
// 该文件测试以下未覆盖的方法:
|
||||
// - ListenTCP:TCP 监听
|
||||
// - Start:服务器启动
|
||||
// - getOrCreateSession:UDP 会话创建
|
||||
// - handleBackendResponse:UDP 后端响应处理
|
||||
// - serve:UDP 服务循环
|
||||
// - startCleanupTicker:UDP 过期清理 ticker
|
||||
//
|
||||
// 作者:xfy
|
||||
package stream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListenTCP_Success(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewServer()
|
||||
|
||||
err := s.ListenTCP("127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
|
||||
s.mu.RLock()
|
||||
require.Len(t, s.listeners, 1)
|
||||
s.mu.RUnlock()
|
||||
|
||||
s.mu.Lock()
|
||||
for _, ln := range s.listeners {
|
||||
_ = ln.Close()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func TestListenTCP_InvalidAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewServer()
|
||||
|
||||
err := s.ListenTCP("256.256.256.256:99999")
|
||||
assert.Error(t, err)
|
||||
|
||||
s.mu.RLock()
|
||||
assert.Empty(t, s.listeners)
|
||||
s.mu.RUnlock()
|
||||
}
|
||||
|
||||
func TestStart_NoListeners(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewServer()
|
||||
|
||||
err := s.Start()
|
||||
require.NoError(t, err)
|
||||
assert.True(t, s.running.Load())
|
||||
|
||||
s.running.Store(false)
|
||||
}
|
||||
|
||||
func TestStart_WithTCPListeners(t *testing.T) {
|
||||
s := NewServer()
|
||||
|
||||
targets := []TargetSpec{
|
||||
{Addr: "127.0.0.1:0", Weight: 1},
|
||||
}
|
||||
_ = s.AddUpstream("test", targets, "round_robin", HealthCheckSpec{})
|
||||
|
||||
err := s.ListenTCP("127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.Start()
|
||||
require.NoError(t, err)
|
||||
assert.True(t, s.running.Load())
|
||||
|
||||
s.running.Store(false)
|
||||
s.mu.RLock()
|
||||
for _, ln := range s.listeners {
|
||||
_ = ln.Close()
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
}
|
||||
|
||||
func TestStart_AcceptConnections(t *testing.T) {
|
||||
s := NewServer()
|
||||
|
||||
backendLn, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
|
||||
go func() {
|
||||
conn, acceptErr := backendLn.Accept()
|
||||
if acceptErr != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
_, _ = io.Copy(conn, conn)
|
||||
}()
|
||||
|
||||
targets := []TargetSpec{
|
||||
{Addr: backendLn.Addr().String(), Weight: 1},
|
||||
}
|
||||
_ = s.AddUpstream("test", targets, "round_robin", HealthCheckSpec{})
|
||||
s.upstreams["test"].targets[0].healthy.Store(true)
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
proxyAddr := ln.Addr().String()
|
||||
|
||||
s.mu.Lock()
|
||||
s.listeners[proxyAddr] = ln
|
||||
s.mu.Unlock()
|
||||
|
||||
err = s.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
clientConn, err := net.DialTimeout("tcp", proxyAddr, 2*time.Second)
|
||||
require.NoError(t, err)
|
||||
|
||||
testData := []byte("hello stream proxy")
|
||||
_, err = clientConn.Write(testData)
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := make([]byte, len(testData))
|
||||
_ = clientConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
n, err := clientConn.Read(buf)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testData, buf[:n])
|
||||
|
||||
_ = clientConn.Close()
|
||||
|
||||
s.running.Store(false)
|
||||
s.mu.RLock()
|
||||
for _, l := range s.listeners {
|
||||
_ = l.Close()
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
_ = backendLn.Close()
|
||||
}
|
||||
|
||||
func TestNewUDPServer_DefaultTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19099"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
|
||||
srv := newUDPServer(conn, upstream, 0)
|
||||
assert.Equal(t, 60*time.Second, srv.timeout)
|
||||
|
||||
srv2 := newUDPServer(conn, upstream, -1*time.Second)
|
||||
assert.Equal(t, 60*time.Second, srv2.timeout)
|
||||
}
|
||||
|
||||
func TestNewUDPServer_CustomTimeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19099"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
|
||||
srv := newUDPServer(conn, upstream, 45*time.Second)
|
||||
assert.Equal(t, 45*time.Second, srv.timeout)
|
||||
}
|
||||
|
||||
func TestSessionKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
addr1, err := net.ResolveUDPAddr("udp", "192.168.1.1:12345")
|
||||
require.NoError(t, err)
|
||||
|
||||
key := sessionKey(addr1)
|
||||
assert.Equal(t, "192.168.1.1:12345", key)
|
||||
|
||||
addr2, err := net.ResolveUDPAddr("udp", "[::1]:54321")
|
||||
require.NoError(t, err)
|
||||
key2 := sessionKey(addr2)
|
||||
assert.Contains(t, key2, "54321")
|
||||
}
|
||||
|
||||
func TestGetSession_NotExist(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19100"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:11111")
|
||||
require.NoError(t, err)
|
||||
|
||||
session := srv.getSession(clientAddr)
|
||||
assert.Nil(t, session)
|
||||
}
|
||||
|
||||
func TestGetSession_Existing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19101"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:22222")
|
||||
require.NoError(t, err)
|
||||
|
||||
oldTime := time.Now().Add(-10 * time.Second)
|
||||
testSession := &udpSession{
|
||||
clientAddr: clientAddr,
|
||||
lastActive: oldTime,
|
||||
srv: srv,
|
||||
}
|
||||
srv.sessions[sessionKey(clientAddr)] = testSession
|
||||
|
||||
session := srv.getSession(clientAddr)
|
||||
require.NotNil(t, session)
|
||||
|
||||
session.mu.RLock()
|
||||
newActive := session.lastActive
|
||||
session.mu.RUnlock()
|
||||
assert.True(t, newActive.After(oldTime))
|
||||
}
|
||||
|
||||
func TestRemoveSession(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19102"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:33333")
|
||||
require.NoError(t, err)
|
||||
|
||||
targetUDPAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
targetConn, err := net.ListenUDP("udp", targetUDPAddr)
|
||||
require.NoError(t, err)
|
||||
defer targetConn.Close()
|
||||
|
||||
testSession := &udpSession{
|
||||
clientAddr: clientAddr,
|
||||
targetConn: targetConn,
|
||||
lastActive: time.Now(),
|
||||
srv: srv,
|
||||
target: &Target{addr: "127.0.0.1:19102"},
|
||||
}
|
||||
srv.sessions[sessionKey(clientAddr)] = testSession
|
||||
|
||||
srv.removeSession(clientAddr)
|
||||
|
||||
srv.mu.RLock()
|
||||
_, exists := srv.sessions[sessionKey(clientAddr)]
|
||||
srv.mu.RUnlock()
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
func TestRemoveSession_NotExist(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19103"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:44444")
|
||||
require.NoError(t, err)
|
||||
|
||||
srv.removeSession(clientAddr)
|
||||
|
||||
srv.mu.RLock()
|
||||
assert.Empty(t, srv.sessions)
|
||||
srv.mu.RUnlock()
|
||||
}
|
||||
|
||||
func TestCleanupExpiredSessions_RemovesExpired(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19104"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, 100*time.Millisecond)
|
||||
|
||||
expiredAddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:55555")
|
||||
expiredSession := &udpSession{
|
||||
clientAddr: expiredAddr,
|
||||
lastActive: time.Now().Add(-1 * time.Hour),
|
||||
srv: srv,
|
||||
}
|
||||
srv.sessions[sessionKey(expiredAddr)] = expiredSession
|
||||
|
||||
activeAddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:55556")
|
||||
activeSession := &udpSession{
|
||||
clientAddr: activeAddr,
|
||||
lastActive: time.Now(),
|
||||
srv: srv,
|
||||
}
|
||||
srv.sessions[sessionKey(activeAddr)] = activeSession
|
||||
|
||||
srv.cleanupExpiredSessions()
|
||||
|
||||
srv.mu.RLock()
|
||||
assert.Len(t, srv.sessions, 1)
|
||||
_, hasActive := srv.sessions[sessionKey(activeAddr)]
|
||||
srv.mu.RUnlock()
|
||||
assert.True(t, hasActive)
|
||||
}
|
||||
|
||||
func TestCleanupExpiredSessions_AllExpired(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19105"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, 1*time.Millisecond)
|
||||
|
||||
for i := range 5 {
|
||||
addr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", 60000+i))
|
||||
sess := &udpSession{
|
||||
clientAddr: addr,
|
||||
lastActive: time.Now().Add(-1 * time.Hour),
|
||||
srv: srv,
|
||||
}
|
||||
srv.sessions[sessionKey(addr)] = sess
|
||||
}
|
||||
|
||||
srv.cleanupExpiredSessions()
|
||||
|
||||
srv.mu.RLock()
|
||||
assert.Empty(t, srv.sessions)
|
||||
srv.mu.RUnlock()
|
||||
}
|
||||
|
||||
func TestGetOrCreateSession_NoHealthyTargets(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19106"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:51111")
|
||||
require.NoError(t, err)
|
||||
|
||||
session, err := srv.getOrCreateSession(clientAddr)
|
||||
assert.Nil(t, session)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGetOrCreateSession_ExistingSession(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19107"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
upstream.targets[0].healthy.Store(true)
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:52222")
|
||||
require.NoError(t, err)
|
||||
|
||||
existingSession := &udpSession{
|
||||
clientAddr: clientAddr,
|
||||
lastActive: time.Now(),
|
||||
srv: srv,
|
||||
}
|
||||
srv.sessions[sessionKey(clientAddr)] = existingSession
|
||||
|
||||
session, err := srv.getOrCreateSession(clientAddr)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, existingSession, session)
|
||||
}
|
||||
|
||||
func TestGetOrCreateSession_NewSession(t *testing.T) {
|
||||
backendAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
backendConn, err := net.ListenUDP("udp", backendAddr)
|
||||
require.NoError(t, err)
|
||||
defer backendConn.Close()
|
||||
|
||||
proxyAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
proxyConn, err := net.ListenUDP("udp", proxyAddr)
|
||||
require.NoError(t, err)
|
||||
defer proxyConn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: backendConn.LocalAddr().String()}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
upstream.targets[0].healthy.Store(true)
|
||||
srv := newUDPServer(proxyConn, upstream, time.Minute)
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:53333")
|
||||
require.NoError(t, err)
|
||||
|
||||
session, err := srv.getOrCreateSession(clientAddr)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, session)
|
||||
assert.Equal(t, clientAddr.String(), session.clientAddr.String())
|
||||
assert.NotNil(t, session.targetConn)
|
||||
|
||||
srv.mu.RLock()
|
||||
stored, exists := srv.sessions[sessionKey(clientAddr)]
|
||||
srv.mu.RUnlock()
|
||||
assert.True(t, exists)
|
||||
assert.Equal(t, session, stored)
|
||||
|
||||
srv.removeSession(clientAddr)
|
||||
srv.wg.Wait()
|
||||
}
|
||||
|
||||
func TestHandleBackendResponse_Timeout(t *testing.T) {
|
||||
proxyAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
proxyConn, err := net.ListenUDP("udp", proxyAddr)
|
||||
require.NoError(t, err)
|
||||
defer proxyConn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19108"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
upstream.targets[0].healthy.Store(true)
|
||||
srv := newUDPServer(proxyConn, upstream, 50*time.Millisecond)
|
||||
|
||||
backendAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
backendConn, err := net.ListenUDP("udp", backendAddr)
|
||||
require.NoError(t, err)
|
||||
defer backendConn.Close()
|
||||
|
||||
clientAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:54444")
|
||||
require.NoError(t, err)
|
||||
|
||||
session := &udpSession{
|
||||
clientAddr: clientAddr,
|
||||
targetConn: backendConn,
|
||||
target: upstream.targets[0],
|
||||
lastActive: time.Now().Add(-1 * time.Hour),
|
||||
srv: srv,
|
||||
}
|
||||
|
||||
srv.mu.Lock()
|
||||
srv.sessions[sessionKey(clientAddr)] = session
|
||||
srv.mu.Unlock()
|
||||
|
||||
srv.wg.Add(1)
|
||||
go session.handleBackendResponse()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
srv.wg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
srv.mu.RLock()
|
||||
_, exists := srv.sessions[sessionKey(clientAddr)]
|
||||
srv.mu.RUnlock()
|
||||
assert.False(t, exists)
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("handleBackendResponse did not finish in time")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServe_ReceivesAndForwards(t *testing.T) {
|
||||
backendAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
backendConn, err := net.ListenUDP("udp", backendAddr)
|
||||
require.NoError(t, err)
|
||||
defer backendConn.Close()
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 65535)
|
||||
for {
|
||||
n, addr, readErr := backendConn.ReadFromUDP(buf)
|
||||
if readErr != nil {
|
||||
return
|
||||
}
|
||||
_, _ = backendConn.WriteToUDP(buf[:n], addr)
|
||||
}
|
||||
}()
|
||||
|
||||
proxyAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
proxyConn, err := net.ListenUDP("udp", proxyAddr)
|
||||
require.NoError(t, err)
|
||||
defer proxyConn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: backendConn.LocalAddr().String()}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
upstream.targets[0].healthy.Store(true)
|
||||
srv := newUDPServer(proxyConn, upstream, 10*time.Second)
|
||||
|
||||
go srv.serve()
|
||||
go srv.startCleanupTicker()
|
||||
|
||||
clientConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0})
|
||||
require.NoError(t, err)
|
||||
defer clientConn.Close()
|
||||
|
||||
testData := []byte("test udp stream")
|
||||
proxyTarget := &net.UDPAddr{
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
Port: proxyConn.LocalAddr().(*net.UDPAddr).Port,
|
||||
}
|
||||
_, err = clientConn.WriteToUDP(testData, proxyTarget)
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := make([]byte, 65535)
|
||||
_ = clientConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
n, _, err := clientConn.ReadFromUDP(buf)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testData, buf[:n])
|
||||
|
||||
close(srv.stopCh)
|
||||
srv.running.Store(false)
|
||||
srv.wg.Wait()
|
||||
}
|
||||
|
||||
func TestStartCleanupTicker_StopsOnSignal(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
require.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
upstream := &Upstream{
|
||||
targets: []*Target{{addr: "127.0.0.1:19110"}},
|
||||
balancer: newRoundRobin(),
|
||||
}
|
||||
srv := newUDPServer(conn, upstream, time.Minute)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
srv.startCleanupTicker()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
close(srv.stopCh)
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("startCleanupTicker did not stop after signal")
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user