lolly/internal/loadbalance/slow_start_test.go
xfy f1dd8cbeb0 fix: complete Stage 1 deep review fixes
Batch 1 - Crash/data corruption:
- Add nil/empty config guards in server and app
- Protect against fasthttp buffer mutation in logging
- Ensure mimeutil falls back before caching empty MIME
- Make proxy health checker and resolver tolerate nil cfg
- Prevent Lua EMERG/ALERT/CRIT log levels from killing process

Batch 2 - Concurrency/race conditions:
- Add focused race tests for compression pool, ssl/ocsp,
  server proxies slice, Lua timer cancel, and TCP socket connect
- Fix Lua timer active race and socket ConnectAsync race

Batch 3 - Resource leaks/functional damage:
- Track and stop rate limiter cleanup goroutines on shutdown
- Add tests for proxy connection count leaks, server pool deadlock,
  Linux sendfile integrity, WebSocket frame data loss,
  stream UDP stop deadlock, and upstream name mismatch
- Fix stream ListenTCP/upstream lookup and UDP shutdown

Batch 4 - High severity technical debt:
- Add nil guard in security headers middleware
- Validate sliding window divisor and add tests
- Protect static handler fields with existing RWMutex
- Avoid mutating live HostClient.Addr on DNS updates
- Fix slow start Start/Stop and resolver restart
- Initialize variable fallback context maps
- Add tests for request_id/time_local and logging file handle close

Also:
- Relax integration variable performance threshold under race detector
- Update benchmark plan docs for new stream ListenTCP signature

Verification:
- make test: pass
- go test -race -count=1 ./internal/...: pass
- make lint: 0 issues
- make build: success
2026-06-17 09:48:43 +08:00

107 lines
2.2 KiB
Go
Raw 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 loadbalance
import (
"sync/atomic"
"testing"
"time"
)
func TestSlowStartManager_StartStopStart(t *testing.T) {
m := NewSlowStartManager(10 * time.Millisecond)
// 第一次启动
m.Start()
if !m.running.Load() {
t.Fatal("manager should be running after first Start")
}
// 停止
m.Stop()
if m.running.Load() {
t.Fatal("manager should be stopped after Stop")
}
// 再次启动:验证 stopCh 被正确重建updateLoop 不会立即退出
m.Start()
if !m.running.Load() {
t.Fatal("manager should be running after second Start")
}
// 等待一段时间,确认 updateLoop 仍在运行
time.Sleep(50 * time.Millisecond)
if !m.running.Load() {
t.Fatal("manager should still be running after sleep")
}
m.Stop()
}
// TestSlowStartManager_SetFindTarget 验证 findTarget 回调被正确使用。
func TestSlowStartManager_SetFindTarget(t *testing.T) {
m := NewSlowStartManager(10 * time.Millisecond)
target := &Target{URL: "http://backend:8080", Weight: 10, SlowStart: 100 * time.Millisecond}
m.OnTargetHealthy(target)
called := atomic.Bool{}
m.SetFindTarget(func(url string) *Target {
called.Store(true)
if url == "http://backend:8080" {
return target
}
return nil
})
m.Start()
defer m.Stop()
// 等待 updateLoop 执行
time.Sleep(50 * time.Millisecond)
if !called.Load() {
t.Error("findTarget callback should be called by updateLoop")
}
}
func TestTarget_GetEffectiveWeight(t *testing.T) {
tests := []struct {
name string
weight int
effectiveWeight int64
want int
}{
{
name: "no slow start",
weight: 10,
effectiveWeight: 0,
want: 10,
},
{
name: "slow start in progress",
weight: 10,
effectiveWeight: 5,
want: 5,
},
{
name: "slow start at 1",
weight: 10,
effectiveWeight: 1,
want: 1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
target := &Target{
Weight: tt.weight,
}
target.EffectiveWeight.Store(tt.effectiveWeight)
got := target.GetEffectiveWeight()
if got != tt.want {
t.Errorf("GetEffectiveWeight() = %d, want %d", got, tt.want)
}
})
}
}