gateway_helper_backoff_test.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package handler
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/require"
  7. )
  8. // --- Task 6.2 验证: math/rand/v2 迁移后 nextBackoff 行为正确 ---
  9. func TestNextBackoff_ExponentialGrowth(t *testing.T) {
  10. // 验证退避时间指数增长(乘数 1.5)
  11. // 由于有随机抖动(±20%),需要验证范围
  12. current := initialBackoff // 100ms
  13. for i := 0; i < 10; i++ {
  14. next := nextBackoff(current)
  15. // 退避结果应在 [initialBackoff, maxBackoff] 范围内
  16. assert.GreaterOrEqual(t, int64(next), int64(initialBackoff),
  17. "第 %d 次退避不应低于初始值 %v", i, initialBackoff)
  18. assert.LessOrEqual(t, int64(next), int64(maxBackoff),
  19. "第 %d 次退避不应超过最大值 %v", i, maxBackoff)
  20. // 为下一轮提供当前退避值
  21. current = next
  22. }
  23. }
  24. func TestNextBackoff_BoundedByMaxBackoff(t *testing.T) {
  25. // 即使输入非常大,输出也不超过 maxBackoff
  26. for i := 0; i < 100; i++ {
  27. result := nextBackoff(10 * time.Second)
  28. assert.LessOrEqual(t, int64(result), int64(maxBackoff),
  29. "退避值不应超过 maxBackoff")
  30. }
  31. }
  32. func TestNextBackoff_BoundedByInitialBackoff(t *testing.T) {
  33. // 即使输入非常小,输出也不低于 initialBackoff
  34. for i := 0; i < 100; i++ {
  35. result := nextBackoff(1 * time.Millisecond)
  36. assert.GreaterOrEqual(t, int64(result), int64(initialBackoff),
  37. "退避值不应低于 initialBackoff")
  38. }
  39. }
  40. func TestNextBackoff_HasJitter(t *testing.T) {
  41. // 验证多次调用会产生不同的值(随机抖动生效)
  42. // 使用相同的输入调用 50 次,收集结果
  43. results := make(map[time.Duration]bool)
  44. current := 500 * time.Millisecond
  45. for i := 0; i < 50; i++ {
  46. result := nextBackoff(current)
  47. results[result] = true
  48. }
  49. // 50 次调用应该至少有 2 个不同的值(抖动存在)
  50. require.Greater(t, len(results), 1,
  51. "nextBackoff 应产生随机抖动,但所有 50 次调用结果相同")
  52. }
  53. func TestNextBackoff_InitialValueGrows(t *testing.T) {
  54. // 验证从初始值开始,退避趋势是增长的
  55. current := initialBackoff
  56. var sum time.Duration
  57. runs := 100
  58. for i := 0; i < runs; i++ {
  59. next := nextBackoff(current)
  60. sum += next
  61. current = next
  62. }
  63. avg := sum / time.Duration(runs)
  64. // 平均退避时间应大于初始值(因为指数增长 + 上限)
  65. assert.Greater(t, int64(avg), int64(initialBackoff),
  66. "平均退避时间应大于初始退避值")
  67. }
  68. func TestNextBackoff_ConvergesToMaxBackoff(t *testing.T) {
  69. // 从初始值开始,经过多次退避后应收敛到 maxBackoff 附近
  70. current := initialBackoff
  71. for i := 0; i < 20; i++ {
  72. current = nextBackoff(current)
  73. }
  74. // 经过 20 次迭代后,应该已经到达 maxBackoff 区间
  75. // 由于抖动,允许 ±20% 的范围
  76. lowerBound := time.Duration(float64(maxBackoff) * 0.8)
  77. assert.GreaterOrEqual(t, int64(current), int64(lowerBound),
  78. "经过多次退避后应收敛到 maxBackoff 附近")
  79. }
  80. func BenchmarkNextBackoff(b *testing.B) {
  81. current := initialBackoff
  82. for i := 0; i < b.N; i++ {
  83. current = nextBackoff(current)
  84. if current > maxBackoff {
  85. current = initialBackoff
  86. }
  87. }
  88. }