mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-04 07:22:13 +08:00
107 lines
3.1 KiB
Go
107 lines
3.1 KiB
Go
|
|
package handler
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"testing"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"github.com/stretchr/testify/assert"
|
|||
|
|
"github.com/stretchr/testify/require"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// --- Task 6.2 验证: math/rand/v2 迁移后 nextBackoff 行为正确 ---
|
|||
|
|
|
|||
|
|
func TestNextBackoff_ExponentialGrowth(t *testing.T) {
|
|||
|
|
// 验证退避时间指数增长(乘数 1.5)
|
|||
|
|
// 由于有随机抖动(±20%),需要验证范围
|
|||
|
|
current := initialBackoff // 100ms
|
|||
|
|
|
|||
|
|
for i := 0; i < 10; i++ {
|
|||
|
|
next := nextBackoff(current)
|
|||
|
|
|
|||
|
|
// 退避结果应在 [initialBackoff, maxBackoff] 范围内
|
|||
|
|
assert.GreaterOrEqual(t, int64(next), int64(initialBackoff),
|
|||
|
|
"第 %d 次退避不应低于初始值 %v", i, initialBackoff)
|
|||
|
|
assert.LessOrEqual(t, int64(next), int64(maxBackoff),
|
|||
|
|
"第 %d 次退避不应超过最大值 %v", i, maxBackoff)
|
|||
|
|
|
|||
|
|
// 为下一轮提供当前退避值
|
|||
|
|
current = next
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNextBackoff_BoundedByMaxBackoff(t *testing.T) {
|
|||
|
|
// 即使输入非常大,输出也不超过 maxBackoff
|
|||
|
|
for i := 0; i < 100; i++ {
|
|||
|
|
result := nextBackoff(10 * time.Second)
|
|||
|
|
assert.LessOrEqual(t, int64(result), int64(maxBackoff),
|
|||
|
|
"退避值不应超过 maxBackoff")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNextBackoff_BoundedByInitialBackoff(t *testing.T) {
|
|||
|
|
// 即使输入非常小,输出也不低于 initialBackoff
|
|||
|
|
for i := 0; i < 100; i++ {
|
|||
|
|
result := nextBackoff(1 * time.Millisecond)
|
|||
|
|
assert.GreaterOrEqual(t, int64(result), int64(initialBackoff),
|
|||
|
|
"退避值不应低于 initialBackoff")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNextBackoff_HasJitter(t *testing.T) {
|
|||
|
|
// 验证多次调用会产生不同的值(随机抖动生效)
|
|||
|
|
// 使用相同的输入调用 50 次,收集结果
|
|||
|
|
results := make(map[time.Duration]bool)
|
|||
|
|
current := 500 * time.Millisecond
|
|||
|
|
|
|||
|
|
for i := 0; i < 50; i++ {
|
|||
|
|
result := nextBackoff(current)
|
|||
|
|
results[result] = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 50 次调用应该至少有 2 个不同的值(抖动存在)
|
|||
|
|
require.Greater(t, len(results), 1,
|
|||
|
|
"nextBackoff 应产生随机抖动,但所有 50 次调用结果相同")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNextBackoff_InitialValueGrows(t *testing.T) {
|
|||
|
|
// 验证从初始值开始,退避趋势是增长的
|
|||
|
|
current := initialBackoff
|
|||
|
|
var sum time.Duration
|
|||
|
|
|
|||
|
|
runs := 100
|
|||
|
|
for i := 0; i < runs; i++ {
|
|||
|
|
next := nextBackoff(current)
|
|||
|
|
sum += next
|
|||
|
|
current = next
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
avg := sum / time.Duration(runs)
|
|||
|
|
// 平均退避时间应大于初始值(因为指数增长 + 上限)
|
|||
|
|
assert.Greater(t, int64(avg), int64(initialBackoff),
|
|||
|
|
"平均退避时间应大于初始退避值")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNextBackoff_ConvergesToMaxBackoff(t *testing.T) {
|
|||
|
|
// 从初始值开始,经过多次退避后应收敛到 maxBackoff 附近
|
|||
|
|
current := initialBackoff
|
|||
|
|
for i := 0; i < 20; i++ {
|
|||
|
|
current = nextBackoff(current)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 经过 20 次迭代后,应该已经到达 maxBackoff 区间
|
|||
|
|
// 由于抖动,允许 ±20% 的范围
|
|||
|
|
lowerBound := time.Duration(float64(maxBackoff) * 0.8)
|
|||
|
|
assert.GreaterOrEqual(t, int64(current), int64(lowerBound),
|
|||
|
|
"经过多次退避后应收敛到 maxBackoff 附近")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func BenchmarkNextBackoff(b *testing.B) {
|
|||
|
|
current := initialBackoff
|
|||
|
|
for i := 0; i < b.N; i++ {
|
|||
|
|
current = nextBackoff(current)
|
|||
|
|
if current > maxBackoff {
|
|||
|
|
current = initialBackoff
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|