mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 00:14:00 +00:00
feat: add authenticated queue recovery
This commit is contained in:
@@ -112,6 +112,53 @@ func TestQueueAPIRejectsUnauthenticatedUnknownAndOversizedInput(t *testing.T) {
|
||||
_ = response.Body.Close()
|
||||
}
|
||||
|
||||
func TestQueueRecoveryAPIIsAuthenticatedOwnerOnlyAndExpiresStaleTickets(t *testing.T) {
|
||||
now := time.Unix(1000, 0).UTC()
|
||||
sessions := domain.NewSessionStore()
|
||||
ownerSession, ownerToken, err := sessions.Issue("player-1", time.Hour, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
otherSession, otherToken, err := sessions.Issue("player-2", time.Hour, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
queue := domain.NewQueue()
|
||||
service := &Service{Sessions: sessions, Queue: queue, 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()
|
||||
create, _ := http.NewRequest(http.MethodPost, server.URL+"/v1/queue", strings.NewReader(`{"ticket_id":"ticket-recovery-123456"}`))
|
||||
create.Header.Set("Authorization", "Bearer "+ownerSession.SessionID+":"+ownerToken)
|
||||
create.Header.Set("Idempotency-Key", "queue-create-recovery-123456")
|
||||
response, err := http.DefaultClient.Do(create)
|
||||
if err != nil || response.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create status=%v err=%v", response.StatusCode, err)
|
||||
}
|
||||
_ = response.Body.Close()
|
||||
get, _ := http.NewRequest(http.MethodGet, server.URL+"/v1/queue/ticket-recovery-123456", nil)
|
||||
get.Header.Set("Authorization", "Bearer "+ownerSession.SessionID+":"+ownerToken)
|
||||
response, err = http.DefaultClient.Do(get)
|
||||
if err != nil || response.StatusCode != http.StatusOK {
|
||||
t.Fatalf("owner recovery status=%v err=%v", response.StatusCode, err)
|
||||
}
|
||||
_ = response.Body.Close()
|
||||
get.Header.Set("Authorization", "Bearer "+otherSession.SessionID+":"+otherToken)
|
||||
response, err = http.DefaultClient.Do(get)
|
||||
if err != nil || response.StatusCode != http.StatusForbidden {
|
||||
t.Fatalf("cross-player recovery status=%v err=%v", response.StatusCode, err)
|
||||
}
|
||||
_ = response.Body.Close()
|
||||
service.Now = func() time.Time { return now.Add(domain.QueueExpiryWindow) }
|
||||
get.Header.Set("Authorization", "Bearer "+ownerSession.SessionID+":"+ownerToken)
|
||||
response, err = http.DefaultClient.Do(get)
|
||||
if err != nil || response.StatusCode != http.StatusGone {
|
||||
t.Fatalf("expired recovery status=%v err=%v", response.StatusCode, err)
|
||||
}
|
||||
_ = response.Body.Close()
|
||||
}
|
||||
|
||||
func TestAuthenticatedProposalAPIUsesRevisionAndIdempotencyPolicy(t *testing.T) {
|
||||
now := time.Unix(1000, 0).UTC()
|
||||
sessions := domain.NewSessionStore()
|
||||
|
||||
Reference in New Issue
Block a user