gateway_soonest_reset_test.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //go:build unit
  2. package service
  3. import (
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/require"
  7. )
  8. func accWithWindowEnd(id int64, end *time.Time) accountWithLoad {
  9. return accountWithLoad{
  10. account: &Account{
  11. ID: id,
  12. Schedulable: true,
  13. Status: StatusActive,
  14. SessionWindowEnd: end,
  15. },
  16. loadInfo: &AccountLoadInfo{AccountID: id},
  17. }
  18. }
  19. func TestFilterBySoonestReset_PicksSoonestFutureWindow(t *testing.T) {
  20. now := time.Now()
  21. soon := now.Add(1 * time.Hour)
  22. later := now.Add(24 * time.Hour)
  23. accounts := []accountWithLoad{
  24. accWithWindowEnd(1, testTimePtr(later)),
  25. accWithWindowEnd(2, testTimePtr(soon)),
  26. accWithWindowEnd(3, testTimePtr(later)),
  27. }
  28. got := filterBySoonestReset(accounts)
  29. require.Len(t, got, 1)
  30. require.Equal(t, int64(2), got[0].account.ID, "重置时间最早的账号被选中")
  31. }
  32. func TestFilterBySoonestReset_IgnoresNilAndExpiredWindows(t *testing.T) {
  33. now := time.Now()
  34. expired := now.Add(-1 * time.Hour)
  35. active := now.Add(2 * time.Hour)
  36. accounts := []accountWithLoad{
  37. accWithWindowEnd(1, nil), // 无活跃窗口
  38. accWithWindowEnd(2, testTimePtr(expired)), // 已过期,视为无活跃窗口
  39. accWithWindowEnd(3, testTimePtr(active)), // 唯一活跃窗口
  40. }
  41. got := filterBySoonestReset(accounts)
  42. require.Len(t, got, 1)
  43. require.Equal(t, int64(3), got[0].account.ID, "仅保留拥有未来重置时间的账号")
  44. }
  45. func TestFilterBySoonestReset_NoActiveWindowReturnsAll(t *testing.T) {
  46. now := time.Now()
  47. expired := now.Add(-30 * time.Minute)
  48. accounts := []accountWithLoad{
  49. accWithWindowEnd(1, nil),
  50. accWithWindowEnd(2, testTimePtr(expired)),
  51. }
  52. got := filterBySoonestReset(accounts)
  53. require.Len(t, got, 2, "没有任何账号拥有活跃窗口时,返回原集合不做过滤")
  54. }
  55. func TestFilterBySoonestReset_TiedSoonestKeepsAll(t *testing.T) {
  56. now := time.Now()
  57. end := now.Add(90 * time.Minute)
  58. accounts := []accountWithLoad{
  59. accWithWindowEnd(1, testTimePtr(end)),
  60. accWithWindowEnd(2, testTimePtr(end)),
  61. accWithWindowEnd(3, testTimePtr(now.Add(5*time.Hour))),
  62. }
  63. got := filterBySoonestReset(accounts)
  64. require.Len(t, got, 2, "并列最早重置的账号都保留,交由后续 LRU 决定")
  65. ids := map[int64]bool{got[0].account.ID: true, got[1].account.ID: true}
  66. require.True(t, ids[1] && ids[2])
  67. }
  68. func TestFilterBySoonestReset_SingleOrEmptyUnchanged(t *testing.T) {
  69. require.Empty(t, filterBySoonestReset(nil))
  70. single := []accountWithLoad{accWithWindowEnd(1, nil)}
  71. require.Len(t, filterBySoonestReset(single), 1)
  72. }