mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-16 04:02:08 +00:00
fix(multiplayer): fence client queue cancellation states
This commit is contained in:
@@ -131,6 +131,9 @@ func (q *Queue) Cancel(playerID, ticketID, idempotencyKey string, expectedRevisi
|
||||
if ticket.Revision != expectedRevision {
|
||||
return QueueTicket{}, ErrStaleRevision
|
||||
}
|
||||
if ticket.State != Queued && ticket.State != Proposed {
|
||||
return QueueTicket{}, fmt.Errorf("%w: cancel in %s", ErrConflict, ticket.State)
|
||||
}
|
||||
if idempotencyKey == "" {
|
||||
return QueueTicket{}, fmt.Errorf("%w: empty cancel key", ErrConflict)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,24 @@ func TestQueueHeartbeatExtendsExpiryExactlyAndRejectsStaleReplay(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueCancelCannotOverrideMatchOwnedLifecycle(t *testing.T) {
|
||||
q := NewQueue()
|
||||
now := time.Unix(1000, 0)
|
||||
candidate := Candidate{TicketID: "ticket-a", PlayerID: "player-a", EnqueuedAt: now}
|
||||
if _, err := q.Create("player-a", "ticket-a", "create-key-123456", candidate, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ticket := q.tickets["ticket-a"]
|
||||
ticket.State = Live
|
||||
q.tickets["ticket-a"] = ticket
|
||||
if _, err := q.Cancel("player-a", "ticket-a", "cancel-key-123456", 0, now.Add(time.Second)); !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("live ticket cancellation error = %v, want conflict", err)
|
||||
}
|
||||
if got := q.tickets["ticket-a"].State; got != Live {
|
||||
t.Fatalf("live ticket state = %s after cancellation attempt", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueExpiryReleasesOwnershipAndDoesNotReturnExpiredCandidates(t *testing.T) {
|
||||
q := NewQueue()
|
||||
now := time.Unix(1000, 0)
|
||||
|
||||
Reference in New Issue
Block a user