feat(accountdelete): drop all-robot games + unspoofable [Deleted] label
Q2=B: DropAllRobotGames deletes the deletee's games with no human opponent (vs-AI or auto-match-robot; children cascade), keeping games with any human seat (anonymized instead). Q1=A: the anon label is the sentinel [Deleted] — the editable-name rule forbids brackets, so no live player can impersonate a deleted account. Integration test covers drop-vs-keep.
This commit is contained in:
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
"scrabble/backend/internal/account"
|
||||
"scrabble/backend/internal/accountdelete"
|
||||
"scrabble/backend/internal/engine"
|
||||
"scrabble/backend/internal/game"
|
||||
)
|
||||
|
||||
// deletedFields reads a tombstoned account's retained real name and its deleted_at.
|
||||
@@ -90,3 +92,44 @@ func TestAnonymizeAndTombstone(t *testing.T) {
|
||||
t.Fatalf("email should be free after deletion, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDropAllRobotGames drops the deletee's solo vs-AI game but keeps a game with a human
|
||||
// opponent.
|
||||
func TestDropAllRobotGames(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gsvc := newGameService()
|
||||
robots := newRobotService(t, gsvc)
|
||||
if err := robots.EnsurePool(ctx); err != nil {
|
||||
t.Fatalf("ensure pool: %v", err)
|
||||
}
|
||||
mm := newMatchmaker(t, robots, time.Minute, 0)
|
||||
deleter := accountdelete.NewDeleter(testDB)
|
||||
|
||||
user := provisionAccount(t)
|
||||
other := provisionAccount(t)
|
||||
|
||||
aiRes, err := mm.StartVsAI(ctx, user, engine.VariantEnglish, true)
|
||||
if err != nil {
|
||||
t.Fatalf("start vs AI: %v", err)
|
||||
}
|
||||
humanGame, err := gsvc.Create(ctx, game.CreateParams{
|
||||
Variant: engine.VariantEnglish, Seats: []uuid.UUID{user, other}, TurnTimeout: time.Hour, Seed: 1,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create human game: %v", err)
|
||||
}
|
||||
|
||||
n, err := deleter.DropAllRobotGames(ctx, user)
|
||||
if err != nil {
|
||||
t.Fatalf("drop: %v", err)
|
||||
}
|
||||
if n != 1 {
|
||||
t.Fatalf("dropped %d games, want 1 (the vs-AI game)", n)
|
||||
}
|
||||
if _, err := gsvc.GameByID(ctx, aiRes.Game.ID); err == nil {
|
||||
t.Error("the vs-AI game should be dropped")
|
||||
}
|
||||
if _, err := gsvc.GameByID(ctx, humanGame.ID); err != nil {
|
||||
t.Errorf("the human game should be kept, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user