mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
fix: bind queue idempotency to compatibility
This commit is contained in:
@@ -221,6 +221,51 @@ func TestQueueCreateRejectsCandidateMetadataMismatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueCreateAPIRetriesIdenticallyAndRejectsKeyReuseWithChangedPayload(t *testing.T) {
|
||||
now := time.Unix(1000, 0).UTC()
|
||||
sessions := domain.NewSessionStore()
|
||||
session, token, err := sessions.Issue("player-1", time.Hour, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := &Service{Sessions: sessions, Queue: domain.NewQueue(), Now: func() time.Time { return now }, Candidate: func(playerID, ticketID string) (domain.Candidate, error) {
|
||||
return domain.Candidate{PlayerID: playerID, TicketID: ticketID, EnqueuedAt: now}, nil
|
||||
}}
|
||||
server := httptest.NewServer(service.Handler())
|
||||
defer server.Close()
|
||||
request := func(body, key string) (int, queueResponse) {
|
||||
req, _ := http.NewRequest(http.MethodPost, server.URL+"/v1/queue", strings.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+session.SessionID+":"+token)
|
||||
req.Header.Set("Idempotency-Key", key)
|
||||
response, requestErr := http.DefaultClient.Do(req)
|
||||
if requestErr != nil {
|
||||
t.Fatal(requestErr)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
var decoded queueResponse
|
||||
if response.StatusCode == http.StatusCreated {
|
||||
if err := json.NewDecoder(response.Body).Decode(&decoded); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
return response.StatusCode, decoded
|
||||
}
|
||||
body := `{"ticket_id":"ticket-idempotent","playlist":"casual","client_build":"build-1","protocol_version":1}`
|
||||
status, first := request(body, "idempotency-key-123456")
|
||||
if status != http.StatusCreated {
|
||||
t.Fatalf("first create status=%d", status)
|
||||
}
|
||||
status, replay := request(body, "idempotency-key-123456")
|
||||
if status != http.StatusCreated || replay != first {
|
||||
t.Fatalf("identical replay status=%d first=%+v replay=%+v", status, first, replay)
|
||||
}
|
||||
changed := `{"ticket_id":"ticket-idempotent","playlist":"casual","client_build":"build-2","protocol_version":1}`
|
||||
status, _ = request(changed, "idempotency-key-123456")
|
||||
if status != http.StatusConflict {
|
||||
t.Fatalf("changed-payload replay status=%d, want conflict", status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueAPIUsesInjectedPersistentBackendWithoutCandidateProvider(t *testing.T) {
|
||||
now := time.Unix(1000, 0).UTC()
|
||||
sessions := domain.NewSessionStore()
|
||||
|
||||
@@ -218,5 +218,5 @@ func createPayload(playerID, ticketID string, candidate Candidate) string {
|
||||
for _, region := range regions {
|
||||
rtts = append(rtts, fmt.Sprintf("%s=%.9f", region, candidate.PredictedRTT[region]))
|
||||
}
|
||||
return strings.Join([]string{playerID, ticketID, candidate.PlayerID, candidate.TicketID, fmt.Sprintf("%.9f", candidate.Rating), candidate.EnqueuedAt.UTC().Format(time.RFC3339Nano), strings.Join(rtts, ",")}, "\x00")
|
||||
return strings.Join([]string{playerID, ticketID, candidate.PlayerID, candidate.TicketID, string(candidate.Playlist), candidate.ClientBuild, fmt.Sprintf("%d", candidate.ProtocolVersion), fmt.Sprintf("%.9f", candidate.Rating), candidate.EnqueuedAt.UTC().Format(time.RFC3339Nano), strings.Join(rtts, ",")}, "\x00")
|
||||
}
|
||||
|
||||
@@ -77,6 +77,21 @@ func TestQueueCreateIdempotencyIncludesCandidatePayload(t *testing.T) {
|
||||
if _, err := q.Create("player-a", "ticket-a", "create-key-123456", changed, now); !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("changed create payload error = %v", err)
|
||||
}
|
||||
changed = base
|
||||
changed.Playlist = Ranked
|
||||
if _, err := q.Create("player-a", "ticket-a", "create-key-123456", changed, now); !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("changed playlist payload error = %v", err)
|
||||
}
|
||||
changed = base
|
||||
changed.ClientBuild = "build-2"
|
||||
if _, err := q.Create("player-a", "ticket-a", "create-key-123456", changed, now); !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("changed build payload error = %v", err)
|
||||
}
|
||||
changed = base
|
||||
changed.ProtocolVersion = 2
|
||||
if _, err := q.Create("player-a", "ticket-a", "create-key-123456", changed, now); !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("changed protocol payload error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueCreateRejectsCandidateOwnedByAnotherPlayer(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user