account_health_test.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package service
  2. import (
  3. "database/sql"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/require"
  7. )
  8. func testHealthCfg() AccountHealthSettings {
  9. return AccountHealthSettings{
  10. Enabled: true, WindowMinutes: 10, MinSamples: 10,
  11. IsolateErrRate: 0.5, RecoverErrRate: 0.2,
  12. CooldownMinutes: 30, IntervalSeconds: 60,
  13. }
  14. }
  15. func TestDecideAccountHealth(t *testing.T) {
  16. now := time.Now()
  17. cfg := testHealthCfg()
  18. // 无样本:健康满分
  19. snap := decideAccountHealth(accountHealthRow{id: 1, name: "a", platform: "openai"}, cfg, now)
  20. require.Equal(t, 100, snap.Score)
  21. require.Equal(t, "healthy", snap.State)
  22. // 样本不足:不隔离
  23. snap = decideAccountHealth(accountHealthRow{id: 1, ok: 3, err: 3}, cfg, now)
  24. require.Equal(t, "healthy", snap.State)
  25. require.Equal(t, 50, snap.Score)
  26. // 错误率达标:隔离
  27. snap = decideAccountHealth(accountHealthRow{id: 1, ok: 4, err: 6}, cfg, now)
  28. require.Equal(t, "isolated", snap.State)
  29. require.Equal(t, 40, snap.Score)
  30. require.True(t, snap.Isolated)
  31. // 中间态:degraded
  32. snap = decideAccountHealth(accountHealthRow{id: 1, ok: 7, err: 3}, cfg, now)
  33. require.Equal(t, "degraded", snap.State)
  34. require.Equal(t, 70, snap.Score)
  35. // 已隔离但窗口无流量:保持 Isolated 标记(不误恢复)
  36. snap = decideAccountHealth(accountHealthRow{
  37. id: 1, reason: sql.NullString{String: "health:auto", Valid: true},
  38. until: sql.NullTime{Time: now.Add(time.Hour), Valid: true},
  39. }, cfg, now)
  40. require.True(t, snap.Isolated)
  41. }
  42. func TestAccountHealthRowPrefix(t *testing.T) {
  43. now := time.Now()
  44. health := accountHealthRow{
  45. reason: sql.NullString{String: "health:auto err_rate=80.0%", Valid: true},
  46. until: sql.NullTime{Time: now.Add(time.Hour), Valid: true},
  47. }
  48. require.True(t, health.isHealthIsolated(now))
  49. other := accountHealthRow{
  50. reason: sql.NullString{String: "ratelimit:429", Valid: true},
  51. until: sql.NullTime{Time: now.Add(time.Hour), Valid: true},
  52. }
  53. require.False(t, other.isHealthIsolated(now))
  54. expired := accountHealthRow{
  55. reason: sql.NullString{String: "health:auto", Valid: true},
  56. until: sql.NullTime{Time: now.Add(-time.Hour), Valid: true},
  57. }
  58. require.False(t, expired.isHealthIsolated(now))
  59. }
  60. func TestNormalizeAccountHealthSettings(t *testing.T) {
  61. norm := normalizeAccountHealthSettings(AccountHealthSettings{})
  62. require.True(t, norm.WindowMinutes > 0)
  63. require.True(t, norm.IsolateErrRate > norm.RecoverErrRate)
  64. // 恢复阈值不得 >= 隔离阈值
  65. norm = normalizeAccountHealthSettings(AccountHealthSettings{RecoverErrRate: 0.9, IsolateErrRate: 0.5})
  66. require.True(t, norm.RecoverErrRate < norm.IsolateErrRate)
  67. require.Equal(t, "50.0%", formatRate(0.5))
  68. }