fix(groups): preserve group traffic totals on global client reset (#7094)

Adjust group baselines before clearing client counters so group usage survives a global reset.
This commit is contained in:
Benjamin Mitchell
2026-11-12 14:36:22 -08:00
committed by GitHub
parent efe768521d
commit 7da8fd23be
3 changed files with 49 additions and 0 deletions
@@ -174,6 +174,40 @@ func TestGroupTotalsSurviveBulkClientReset(t *testing.T) {
} }
} }
func TestGroupTotalsSurviveGlobalClientReset(t *testing.T) {
initTrafficTestDB(t)
svc := &ClientService{}
seedGroupedClient(t, "alice", "reset", 100, 200)
seedGroupedClient(t, "bob", "unreset", 40, 60)
if err := svc.ResetGroupTraffic("reset"); err != nil {
t.Fatalf("ResetGroupTraffic: %v", err)
}
if _, err := svc.ResetAllTraffics(); err != nil {
t.Fatalf("ResetAllTraffics: %v", err)
}
if g := groupByName(t, svc, "unreset"); g.Up != 40 || g.Down != 60 || g.TrafficUsed != 100 {
t.Fatalf("global reset changed accumulated group usage: got %+v, want up=40 down=60 used=100", g)
}
var traffic xray.ClientTraffic
if err := database.GetDB().Where("email = ?", "alice").First(&traffic).Error; err != nil {
t.Fatalf("load alice traffic: %v", err)
}
if traffic.Up != 0 || traffic.Down != 0 {
t.Fatalf("client traffic not reset: up=%d down=%d", traffic.Up, traffic.Down)
}
if err := database.GetDB().Model(&traffic).
Updates(map[string]any{"up": 10, "down": 20}).Error; err != nil {
t.Fatalf("record new alice traffic: %v", err)
}
if g := groupByName(t, svc, "reset"); g.Up != 10 || g.Down != 20 || g.TrafficUsed != 30 {
t.Fatalf("global reset hid new group usage: got %+v, want up=10 down=20 used=30", g)
}
}
func TestGroupTotalsSurviveClientDelete(t *testing.T) { func TestGroupTotalsSurviveClientDelete(t *testing.T) {
initTrafficTestDB(t) initTrafficTestDB(t)
csvc := &ClientService{} csvc := &ClientService{}
+12
View File
@@ -67,6 +67,14 @@ func adjustGroupBaselinesForRemovedTraffic(tx *gorm.DB, emails []string) error {
return shiftGroupBaselines(tx, emails, -1) return shiftGroupBaselines(tx, emails, -1)
} }
func adjustAllGroupBaselinesForRemovedTraffic(tx *gorm.DB) error {
totals, err := sumGroupTraffic(tx, "c.group_name <> ''")
if err != nil {
return err
}
return applyGroupBaselineShift(tx, totals, -1)
}
// adjustGroupBaselinesForRestoredTraffic shifts group baselines up by counters an // adjustGroupBaselinesForRestoredTraffic shifts group baselines up by counters an
// import restored, so usage from before the import never enters a group total. // import restored, so usage from before the import never enters a group total.
func adjustGroupBaselinesForRestoredTraffic(tx *gorm.DB, emails []string) error { func adjustGroupBaselinesForRestoredTraffic(tx *gorm.DB, emails []string) error {
@@ -92,6 +100,10 @@ func shiftGroupBaselines(tx *gorm.DB, emails []string, sign int64) error {
} }
} }
} }
return applyGroupBaselineShift(tx, totals, sign)
}
func applyGroupBaselineShift(tx *gorm.DB, totals map[string]*groupCounters, sign int64) error {
for name, d := range totals { for name, d := range totals {
if d.up == 0 && d.down == 0 { if d.up == 0 && d.down == 0 {
continue continue
+3
View File
@@ -252,6 +252,9 @@ func (s *ClientService) ResetAllTraffics() (bool, error) {
if qErr != nil { if qErr != nil {
return qErr return qErr
} }
if err := adjustAllGroupBaselinesForRemovedTraffic(tx); err != nil {
return err
}
if affected, qErr = zeroClientTraffics(tx, nil, keepOff); qErr != nil { if affected, qErr = zeroClientTraffics(tx, nil, keepOff); qErr != nil {
return qErr return qErr
} }