feat(chat): a message to a disguised robot opponent is born read
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 49s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m21s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 49s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m21s
A pooled robot substituted into an ordinary (non-AI) game never opens the chat, so a text message to it would linger unread forever — skewing the unread count and the publish-to-read metric. Clear its recipient bit at PostMessage time (robotRecipients via account.IsRobot), so the message is born read. The human sender never had their own message unread, so this is invisible to them; a nudge to a robot already self-clears when the robot answers by moving.
This commit is contained in:
@@ -5,9 +5,13 @@ package inttest
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"scrabble/backend/internal/account"
|
||||
"scrabble/backend/internal/engine"
|
||||
"scrabble/backend/internal/game"
|
||||
"scrabble/backend/internal/social"
|
||||
)
|
||||
|
||||
@@ -116,6 +120,43 @@ func TestNudgeClearedByMove(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestChatToRobotIsBornRead checks a text message to a disguised robot opponent (a pooled
|
||||
// robot substituted into an ordinary, non-AI game) is born read: the robot never opens the
|
||||
// chat, so the message must not linger unread (skewing the count and the read metric).
|
||||
func TestChatToRobotIsBornRead(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc := newSocialService()
|
||||
human := provisionAccount(t)
|
||||
robot, err := account.NewStore(testDB).ProvisionRobot(ctx, "robot-chat-"+uuid.NewString(), "Robbie")
|
||||
if err != nil {
|
||||
t.Fatalf("provision robot: %v", err)
|
||||
}
|
||||
g, err := newGameService().Create(ctx, game.CreateParams{
|
||||
Variant: engine.VariantEnglish, Seats: []uuid.UUID{human, robot.ID},
|
||||
TurnTimeout: 24 * time.Hour, Seed: openingSeed(t),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create game: %v", err)
|
||||
}
|
||||
// The human (seat 0, to move) chats the disguised robot; the message is born read.
|
||||
msg, err := svc.PostMessage(ctx, g.ID, human, "good luck", "")
|
||||
if err != nil {
|
||||
t.Fatalf("post: %v", err)
|
||||
}
|
||||
if items, _ := svc.AdminListMessages(ctx, social.AdminMessageFilter{GameID: g.ID, UnreadOnly: true}, 50, 0); len(items) != 0 {
|
||||
t.Errorf("a message to a robot should be born read, but the unread filter listed %d", len(items))
|
||||
}
|
||||
card, err := svc.AdminMessageDetail(ctx, msg.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("detail: %v", err)
|
||||
}
|
||||
for _, s := range card.Seats {
|
||||
if s.AccountID == robot.ID && s.Role != "read" {
|
||||
t.Errorf("robot seat role = %q, want read", s.Role)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestAdminChatUnreadFilterAndDetail checks the admin unread-only filter and the per-seat read
|
||||
// breakdown of the message card.
|
||||
func TestAdminChatUnreadFilterAndDetail(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user