1
0

client_update_keepalive_test.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package service
  2. import (
  3. "testing"
  4. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  5. )
  6. func inboundKeepAlive(t *testing.T, inboundSvc *InboundService, ibId int, email string) int {
  7. t.Helper()
  8. ib, err := inboundSvc.GetInbound(ibId)
  9. if err != nil {
  10. t.Fatalf("GetInbound %d: %v", ibId, err)
  11. }
  12. clients, err := inboundSvc.GetClients(ib)
  13. if err != nil {
  14. t.Fatalf("GetClients %d: %v", ibId, err)
  15. }
  16. for i := range clients {
  17. if clients[i].Email == email {
  18. return clients[i].KeepAliveSeconds()
  19. }
  20. }
  21. t.Fatalf("email %q not found on inbound %d", email, ibId)
  22. return 0
  23. }
  24. // seedKeepAliveClient attaches one WireGuard client already carrying a
  25. // PersistentKeepalive, and returns its inbound and client-record id.
  26. func seedKeepAliveClient(t *testing.T, email string, keepAlive int) (*model.Inbound, int) {
  27. t.Helper()
  28. svc := &ClientService{}
  29. seeded := model.Client{
  30. Email: email,
  31. SubID: "sub-" + email,
  32. Enable: true,
  33. AllowedIPs: []string{"10.0.0.5/32"},
  34. KeepAlive: model.KeepAlivePtr(keepAlive),
  35. }
  36. ib := mkInbound(t, 51820, model.WireGuard, clientsSettings(t, []model.Client{seeded}))
  37. if err := svc.SyncInbound(nil, ib.Id, []model.Client{seeded}); err != nil {
  38. t.Fatalf("seed linkage: %v", err)
  39. }
  40. return ib, lookupClientRecord(t, email).Id
  41. }
  42. // Carrying forward on a zero incoming keepalive was a 0 -> 0 no-op while no UI
  43. // could set the field; once the client form could, "0 disables it" was unreachable.
  44. func TestUpdateCanClearKeepAliveOnAnExistingClient(t *testing.T) {
  45. setupBulkDB(t)
  46. inboundSvc := &InboundService{}
  47. svc := &ClientService{}
  48. ib, recId := seedKeepAliveClient(t, "ka@x", 25)
  49. if got := inboundKeepAlive(t, inboundSvc, ib.Id, "ka@x"); got != 25 {
  50. t.Fatalf("seeded keepAlive = %d, want 25", got)
  51. }
  52. updated := model.Client{
  53. Email: "ka@x",
  54. Enable: true,
  55. AllowedIPs: []string{"10.0.0.5/32"},
  56. KeepAlive: model.KeepAlivePtr(0),
  57. }
  58. if _, err := svc.Update(inboundSvc, recId, updated, 0); err != nil {
  59. t.Fatalf("Update: %v", err)
  60. }
  61. if got := inboundKeepAlive(t, inboundSvc, ib.Id, "ka@x"); got != 0 {
  62. t.Fatalf("inbound keepAlive after an explicit 0 = %d, want 0", got)
  63. }
  64. if got := lookupClientRecord(t, "ka@x").KeepAlive; got != 0 {
  65. t.Fatalf("stored wg_keep_alive after an explicit 0 = %d, want 0", got)
  66. }
  67. }
  68. // The other half of the contract: a payload that never mentions keepAlive (a
  69. // metadata-only edit from the bot or the API) leaves the stored value alone.
  70. func TestUpdateWithoutKeepAlivePreservesTheStoredValue(t *testing.T) {
  71. setupBulkDB(t)
  72. inboundSvc := &InboundService{}
  73. svc := &ClientService{}
  74. ib, recId := seedKeepAliveClient(t, "ka@x", 25)
  75. updated := model.Client{
  76. Email: "ka@x",
  77. Enable: true,
  78. AllowedIPs: []string{"10.0.0.5/32"},
  79. }
  80. if _, err := svc.Update(inboundSvc, recId, updated, 0); err != nil {
  81. t.Fatalf("Update: %v", err)
  82. }
  83. if got := inboundKeepAlive(t, inboundSvc, ib.Id, "ka@x"); got != 25 {
  84. t.Fatalf("inbound keepAlive after an edit that omitted it = %d, want 25", got)
  85. }
  86. if got := lookupClientRecord(t, "ka@x").KeepAlive; got != 25 {
  87. t.Fatalf("stored wg_keep_alive after an edit that omitted it = %d, want 25", got)
  88. }
  89. }