mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-14 07:32:10 +00:00
feat: add ranked reconnect policy
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testRoster(now time.Time) []JoinAuthorisation {
|
||||
roster := make([]JoinAuthorisation, 6)
|
||||
for i := range roster {
|
||||
roster[i] = JoinAuthorisation{MatchID: "match-1", ServerID: "server-1", Protocol: "v1", PlayerID: string(rune('a' + i)), Slot: i, Team: i % 2, Generation: 1, ExpiresAt: now.Add(time.Hour)}
|
||||
}
|
||||
return roster
|
||||
}
|
||||
|
||||
func TestRankedReconnectReclaimsWithinGraceAndFencesOldGeneration(t *testing.T) {
|
||||
now := time.Unix(1000, 0)
|
||||
r, err := NewRankedConnections("match-1", "server-1", "v1", testRoster(now))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
auth := testRoster(now)[0]
|
||||
if gen, err := r.Admit(auth, now); err != nil || gen != 1 {
|
||||
t.Fatalf("initial admit = %d, %v", gen, err)
|
||||
}
|
||||
if err := r.Disconnect("a", 1, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if gen, err := r.Admit(auth, now.Add(RankedReconnectGrace)); err != nil || gen != 2 {
|
||||
t.Fatalf("boundary reclaim = %d, %v", gen, err)
|
||||
}
|
||||
if err := r.Disconnect("a", 1, now.Add(31*time.Second)); !errors.Is(err, ErrConnectionFenced) {
|
||||
t.Fatalf("old connection was not fenced: %v", err)
|
||||
}
|
||||
if err := r.Disconnect("a", 2, now.Add(31*time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if gen, err := r.Admit(auth, now.Add(32*time.Second)); err != nil || gen != 3 {
|
||||
t.Fatalf("repeated reclaim with existing authorisation = %d, %v", gen, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankedReconnectRejectsWrongBindingAndExpiredGrace(t *testing.T) {
|
||||
now := time.Unix(1000, 0)
|
||||
r, err := NewRankedConnections("match-1", "server-1", "v1", testRoster(now))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bad := testRoster(now)[0]
|
||||
bad.ServerID = "server-2"
|
||||
if _, err := r.Admit(bad, now); !errors.Is(err, ErrJoinAuthorisation) {
|
||||
t.Fatalf("wrong server accepted: %v", err)
|
||||
}
|
||||
if err := r.Disconnect("a", 1, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := r.Admit(testRoster(now)[0], now.Add(RankedReconnectGrace+time.Nanosecond)); !errors.Is(err, ErrReconnectExpired) {
|
||||
t.Fatalf("expired reclaim error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankedAbandonCooldownUsesRollingSevenDayLadder(t *testing.T) {
|
||||
now := time.Unix(1000, 0)
|
||||
r, err := NewRankedConnections("match-1", "server-1", "v1", testRoster(now))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := r.Disconnect("a", 1, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
history := map[string][]time.Time{"a": {now.Add(-6 * 24 * time.Hour), now.Add(-time.Hour), now.Add(-8 * 24 * time.Hour)}}
|
||||
got := r.ExpireGrace(now.Add(RankedReconnectGrace+time.Second), history)
|
||||
if len(got) != 1 || got[0].PlayerID != "a" || got[0].Cooldown != time.Hour {
|
||||
t.Fatalf("unexpected abandonment: %+v", got)
|
||||
}
|
||||
if again := r.ExpireGrace(now.Add(2*time.Minute), history); len(again) != 0 {
|
||||
t.Fatalf("abandonment repeated: %+v", again)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user