client_traffic_reset_order_test.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. // A reset of a quota-disabled client must end enabled even when a traffic tick
  10. // runs between its steps: enabling before zeroing lets the tick re-disable it.
  11. func TestResetTrafficOfDepletedClientSurvivesTickMidReset(t *testing.T) {
  12. resets := []struct {
  13. name string
  14. run func() error
  15. }{
  16. {"single", func() error {
  17. _, err := (&ClientService{}).ResetTrafficByEmail(&InboundService{}, "d@stale")
  18. return err
  19. }},
  20. {"bulk", func() error {
  21. _, err := (&ClientService{}).BulkResetTraffic(&InboundService{}, []string{"d@stale"})
  22. return err
  23. }},
  24. }
  25. for _, reset := range resets {
  26. t.Run(reset.name, func(t *testing.T) {
  27. requireResetSurvivesTick(t, reset.run)
  28. })
  29. }
  30. }
  31. func requireResetSurvivesTick(t *testing.T, reset func() error) {
  32. t.Helper()
  33. setupBulkDB(t)
  34. clients := []model.Client{{Email: "d@stale", ID: "aaaaaaaa-0000-0000-0000-00000000000d", SubID: "sub-d", Enable: false, TotalGB: 1000}}
  35. ib := mkInbound(t, 23140, model.VLESS, clientsSettings(t, clients))
  36. if err := (&ClientService{}).SyncInbound(nil, ib.Id, clients); err != nil {
  37. t.Fatalf("SyncInbound: %v", err)
  38. }
  39. row := xray.ClientTraffic{InboundId: ib.Id, Email: "d@stale", Enable: false, Up: 600, Down: 400, Total: 1000}
  40. if err := database.GetDB().Create(&row).Error; err != nil {
  41. t.Fatalf("seed client_traffics: %v", err)
  42. }
  43. resetTrafficWriterForTest(t)
  44. StartTrafficWriter()
  45. parked := make(chan struct{})
  46. release := make(chan struct{})
  47. go func() {
  48. _ = submitTrafficWrite(func() error {
  49. close(parked)
  50. <-release
  51. return nil
  52. })
  53. }()
  54. <-parked
  55. resetDone := make(chan error, 1)
  56. go func() { resetDone <- reset() }()
  57. waitTrafficWriterQueued(t)
  58. tickDone := make(chan error, 1)
  59. go func() {
  60. _, _, err := (&InboundService{}).AddTraffic(nil, nil)
  61. tickDone <- err
  62. }()
  63. deadline := time.Now().Add(5 * time.Second)
  64. for len(twQueue) < 2 && time.Now().Before(deadline) {
  65. time.Sleep(time.Millisecond)
  66. }
  67. close(release)
  68. if err := <-resetDone; err != nil {
  69. t.Fatalf("reset: %v", err)
  70. }
  71. if err := <-tickDone; err != nil {
  72. t.Fatalf("AddTraffic: %v", err)
  73. }
  74. var after xray.ClientTraffic
  75. if err := database.GetDB().Where("email = ?", "d@stale").First(&after).Error; err != nil {
  76. t.Fatalf("read client_traffics: %v", err)
  77. }
  78. c, _ := settingsClient(t, ib.Id, "d@stale")
  79. rec := lookupClientRecord(t, "d@stale")
  80. if !after.Enable || !c.Enable || !rec.Enable || after.Up+after.Down != 0 {
  81. t.Fatalf("after reset: traffic enable=%v used=%d, settings enable=%v, record enable=%v; want all enabled at 0",
  82. after.Enable, after.Up+after.Down, c.Enable, rec.Enable)
  83. }
  84. }