inbound_autorenew_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package service
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database"
  6. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  7. "github.com/mhsanaei/3x-ui/v3/internal/xray"
  8. )
  9. // TestAutoRenewClients_MultiInbound covers the renew loop across more than one
  10. // inbound: every expired client with reset>0 must get a fresh future expiry,
  11. // zeroed usage and re-enabled state, while a non-expiring client is untouched.
  12. // It also guards the map-lookup refactor of the old quadratic inner loop.
  13. func TestAutoRenewClients_MultiInbound(t *testing.T) {
  14. setupBulkDB(t)
  15. svc := &InboundService{}
  16. db := database.GetDB()
  17. past := time.Now().Add(-48 * time.Hour).UnixMilli()
  18. future := time.Now().Add(365 * 24 * time.Hour).UnixMilli()
  19. // Two inbounds, two expiring clients each, plus one client that never expires.
  20. ib1Clients := []model.Client{
  21. {Email: "a@x", ID: "11111111-1111-1111-1111-111111111111", Enable: false, Reset: 30, ExpiryTime: past},
  22. {Email: "b@x", ID: "22222222-2222-2222-2222-222222222222", Enable: false, Reset: 30, ExpiryTime: past},
  23. }
  24. ib2Clients := []model.Client{
  25. {Email: "c@x", ID: "33333333-3333-3333-3333-333333333333", Enable: false, Reset: 7, ExpiryTime: past},
  26. {Email: "keep@x", ID: "44444444-4444-4444-4444-444444444444", Enable: true, Reset: 0, ExpiryTime: future},
  27. }
  28. ib1 := mkInbound(t, 30001, model.VLESS, clientsSettings(t, ib1Clients))
  29. ib2 := mkInbound(t, 30002, model.VLESS, clientsSettings(t, ib2Clients))
  30. if err := svc.clientService.SyncInbound(nil, ib1.Id, ib1Clients); err != nil {
  31. t.Fatalf("SyncInbound ib1: %v", err)
  32. }
  33. if err := svc.clientService.SyncInbound(nil, ib2.Id, ib2Clients); err != nil {
  34. t.Fatalf("SyncInbound ib2: %v", err)
  35. }
  36. // Seed traffic rows: expired+depleted for the three renewable clients, and a
  37. // healthy row for keep@x.
  38. rows := []xray.ClientTraffic{
  39. {InboundId: ib1.Id, Email: "a@x", Enable: false, Up: 100, Down: 200, Reset: 30, ExpiryTime: past},
  40. {InboundId: ib1.Id, Email: "b@x", Enable: false, Up: 300, Down: 400, Reset: 30, ExpiryTime: past},
  41. {InboundId: ib2.Id, Email: "c@x", Enable: false, Up: 500, Down: 600, Reset: 7, ExpiryTime: past},
  42. {InboundId: ib2.Id, Email: "keep@x", Enable: true, Up: 1, Down: 2, Reset: 0, ExpiryTime: future},
  43. }
  44. if err := db.Create(&rows).Error; err != nil {
  45. t.Fatalf("seed client_traffics: %v", err)
  46. }
  47. if _, count, err := svc.autoRenewClients(db); err != nil {
  48. t.Fatalf("autoRenewClients: %v", err)
  49. } else if count != 3 {
  50. t.Fatalf("renewed count = %d, want 3", count)
  51. }
  52. now := time.Now().UnixMilli()
  53. for _, email := range []string{"a@x", "b@x", "c@x"} {
  54. var row xray.ClientTraffic
  55. if err := db.Where("email = ?", email).First(&row).Error; err != nil {
  56. t.Fatalf("read %s: %v", email, err)
  57. }
  58. if row.Up != 0 || row.Down != 0 {
  59. t.Errorf("%s: usage not reset: up=%d down=%d", email, row.Up, row.Down)
  60. }
  61. if !row.Enable {
  62. t.Errorf("%s: not re-enabled", email)
  63. }
  64. if row.ExpiryTime <= now {
  65. t.Errorf("%s: expiry not advanced: got %d, now %d", email, row.ExpiryTime, now)
  66. }
  67. }
  68. // The non-expiring client must be left exactly as seeded.
  69. var keep xray.ClientTraffic
  70. if err := db.Where("email = ?", "keep@x").First(&keep).Error; err != nil {
  71. t.Fatalf("read keep@x: %v", err)
  72. }
  73. if keep.Up != 1 || keep.Down != 2 || keep.ExpiryTime != future {
  74. t.Errorf("keep@x was modified: %+v", keep)
  75. }
  76. // The renewed state must also be reflected in the inbound settings JSON.
  77. reloaded, err := svc.GetInbound(ib1.Id)
  78. if err != nil {
  79. t.Fatalf("GetInbound ib1: %v", err)
  80. }
  81. cs, err := svc.GetClients(reloaded)
  82. if err != nil {
  83. t.Fatalf("GetClients ib1: %v", err)
  84. }
  85. for _, c := range cs {
  86. if !c.Enable {
  87. t.Errorf("settings client %s still disabled after renew", c.Email)
  88. }
  89. if c.ExpiryTime <= now {
  90. t.Errorf("settings client %s expiry not advanced: %d", c.Email, c.ExpiryTime)
  91. }
  92. }
  93. }