feat: backend service

This commit is contained in:
Ilia Denisov
2026-05-06 10:14:55 +03:00
committed by GitHub
parent 3e2622757e
commit f446c6a2ac
1486 changed files with 49720 additions and 266401 deletions
+76
View File
@@ -0,0 +1,76 @@
package testenv
import (
"context"
"encoding/json"
"fmt"
"net/http"
"testing"
)
// Pilot bundles a registered Session with its resolved user_id and a
// pre-built BackendUserClient so tests do not have to repeat the
// resolution dance for each redeem call.
type Pilot struct {
Session *Session
UserID string
HTTP *BackendUserClient
RaceName string
}
// EnrollPilots registers `count` pilots with synthetic
// `Player01..PlayerNN` race names and the matching
// `playerNN+suffix@example.com` emails, then has owner issue an
// invite for each one and the pilot redeem it. The game must be in
// `enrollment_open` (or any state that accepts invites + redeem).
//
// The helper exists because the engine's `/api/v1/admin/init` enforces
// `len(races) >= 10`, so any runtime-driven scenario needs at least
// ten enrolled members. Using it from tests keeps each pilot a real
// authenticated user, exactly mirroring how operators would seed a
// production game.
func EnrollPilots(t *testing.T, plat *Platform, ownerHTTP *BackendUserClient, gameID string, count int, suffix string) []*Pilot {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
pilots := make([]*Pilot, 0, count)
for i := 1; i <= count; i++ {
raceName := fmt.Sprintf("Player%02d", i)
email := fmt.Sprintf("player%02d+%s@example.com", i, suffix)
sess := RegisterSession(t, plat, email)
userID, err := sess.LookupUserID(ctx, plat)
if err != nil {
t.Fatalf("pilot %s: resolve user_id: %v", raceName, err)
}
raw, resp, err := ownerHTTP.Do(ctx, http.MethodPost, "/api/v1/user/lobby/games/"+gameID+"/invites", map[string]any{
"invited_user_id": userID,
"race_name": raceName,
})
if err != nil || resp.StatusCode != http.StatusCreated {
t.Fatalf("pilot %s: issue invite: err=%v status=%d body=%s", raceName, err, resp.StatusCode, string(raw))
}
var invite struct {
InviteID string `json:"invite_id"`
}
if err := json.Unmarshal(raw, &invite); err != nil {
t.Fatalf("pilot %s: decode invite: %v", raceName, err)
}
pilotHTTP := NewBackendUserClient(plat.Backend.HTTPURL, userID)
raw, resp, err = pilotHTTP.Do(ctx, http.MethodPost, "/api/v1/user/lobby/games/"+gameID+"/invites/"+invite.InviteID+"/redeem", nil)
if err != nil || resp.StatusCode/100 != 2 {
t.Fatalf("pilot %s: redeem: err=%v status=%d body=%s", raceName, err, resp.StatusCode, string(raw))
}
pilots = append(pilots, &Pilot{
Session: sess,
UserID: userID,
HTTP: pilotHTTP,
RaceName: raceName,
})
}
return pilots
}