Files

139 lines
5.7 KiB
Go

package domain
import (
"errors"
"testing"
"time"
)
func testBinding() WorkloadBinding {
return WorkloadBinding{Issuer: "https://issuer", Audience: "cosmic-result", Namespace: "games", ServiceAcct: "match-server", PodUID: "pod-1", GameServerUID: "gs-1", AllocationID: "allocation-1", MatchID: "match-1", ServerID: "server-1"}
}
func testResult() MatchResult {
return MatchResult{MatchID: "match-1", ServerID: "server-1", ResultNonce: "nonce-1234567890", Team0Score: 3, Team1Score: 2, IntegrityState: IntegrityCertified}
}
func TestResultStoreBindsWorkloadAndMakesIdenticalDuplicateInert(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, err := NewResultStore(binding)
if err != nil {
t.Fatal(err)
}
first, created, err := store.Submit("result-1", testResult(), binding, now)
if err != nil || !created || !RatingEligible(first) {
t.Fatalf("first result = %+v created=%v err=%v", first, created, err)
}
replay, created, err := store.Submit("result-1", testResult(), binding, now.Add(time.Minute))
if err != nil || created || replay.ReceivedAt != now {
t.Fatalf("duplicate result = %+v created=%v err=%v", replay, created, err)
}
wrong := binding
wrong.PodUID = "pod-2"
if _, _, err := store.Submit("result-2", testResult(), wrong, now); !errors.Is(err, ErrResultBinding) {
t.Fatalf("wrong pod accepted: %v", err)
}
}
func TestResultStoreRejectsMissingAuthoritativeTime(t *testing.T) {
binding := testBinding()
store, err := NewResultStore(binding)
if err != nil {
t.Fatal(err)
}
if _, _, err := store.Submit("result-1", testResult(), binding, time.Time{}); !errors.Is(err, ErrResultInvalid) {
t.Fatalf("zero-time result error = %v", err)
}
}
func TestResultStoreAcceptsDurablyBoundSignedWorkloadIdentity(t *testing.T) {
// Signed workload tokens resolve this three-part binding from the durable
// allocation record; they intentionally carry no Kubernetes JWT claims.
binding := WorkloadBinding{AllocationID: "allocation-1", MatchID: "match-1", ServerID: "server-1"}
if _, err := NewResultStore(binding); err != nil {
t.Fatalf("signed workload binding rejected: %v", err)
}
partial := binding
partial.Issuer = "https://issuer"
if _, err := NewResultStore(partial); !errors.Is(err, ErrResultBinding) {
t.Fatalf("partial Kubernetes identity error = %v, want ErrResultBinding", err)
}
}
func TestConflictingResultIsInertAndIntegritySuppressesRating(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, _ := NewResultStore(binding)
if _, _, err := store.Submit("result-1", testResult(), binding, now); err != nil {
t.Fatal(err)
}
conflict := testResult()
conflict.Team0Score = 99
prior, _, err := store.Submit("result-2", conflict, binding, now)
if !errors.Is(err, ErrResultConflict) || prior.ResultID != "result-1" || prior.CommittedAt != (time.Time{}) {
t.Fatalf("conflict mutated receipt: %+v err=%v", prior, err)
}
suppressed := testResult()
suppressed.MatchID = "match-2"
suppressed.IntegrityState = IntegritySuppressed
secondBinding := binding
secondBinding.MatchID = "match-2"
secondStore, _ := NewResultStore(secondBinding)
got, _, err := secondStore.Submit("result-2", suppressed, secondBinding, now)
if err != nil || RatingEligible(got) {
t.Fatalf("suppressed result eligibility = %+v err=%v", got, err)
}
}
func TestAnnotationReconcileChecksSignatureAndDigest(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, _ := NewResultStore(binding)
result := testResult()
annotation := ResultAnnotation{ResultID: "result-1", Result: result, PayloadDigest: resultDigest(result), Signature: []byte("sig")}
verify := func(candidate ResultAnnotation) bool { return string(candidate.Signature) == "sig" }
if _, created, err := store.Reconcile(annotation, verify, binding, now); err != nil || !created {
t.Fatalf("valid annotation = created=%v err=%v", created, err)
}
forged := annotation
forged.Result.Team0Score = 99
if _, _, err := store.Reconcile(forged, verify, binding, now); !errors.Is(err, ErrResultBinding) {
t.Fatalf("forged annotation accepted: %v", err)
}
}
func TestResultDeliveryHealthSeparatesOutageFromIntegrity(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, _ := NewResultStore(binding)
receipt, _, err := store.Submit("result-1", testResult(), binding, now)
if err != nil {
t.Fatal(err)
}
if DeliveryStatus(receipt, now.Add(5*time.Minute-time.Nanosecond)) != DeliveryHealthy || DeliveryStatus(receipt, now.Add(ResultDeliveryAlertAfter)) != DeliveryAlert || DeliveryStatus(receipt, now.Add(ResultDeliveryReviewAfter)) != DeliveryReview {
t.Fatal("pending delivery thresholds are wrong")
}
committed, err := store.Commit("result-1", "match-1", now.Add(31*time.Minute))
if err != nil || DeliveryStatus(committed, now.Add(2*time.Hour)) != DeliveryHealthy {
t.Fatalf("committed delivery status = %+v err=%v", committed, err)
}
}
func TestIntegrityClassifierDoesNotSuppressHealthyResultForDeliveryOutage(t *testing.T) {
healthy := IntegrityEvidence{RosterAuthoritative: true, SimulationAuthoritative: true, ResultAuthoritative: true, RegionalPlayFair: true, DeliveryAvailable: false}
if got := ClassifyIntegrity(healthy); got != IntegrityCertified {
t.Fatalf("delivery outage changed integrity: %s", got)
}
for _, evidence := range []IntegrityEvidence{
{SimulationAuthoritative: true, ResultAuthoritative: true, RegionalPlayFair: true},
{RosterAuthoritative: true, ResultAuthoritative: true, RegionalPlayFair: true},
{RosterAuthoritative: true, SimulationAuthoritative: true, RegionalPlayFair: true},
{RosterAuthoritative: true, SimulationAuthoritative: true, ResultAuthoritative: true},
} {
if got := ClassifyIntegrity(evidence); got != IntegritySuppressed {
t.Fatalf("incomplete integrity was certified: %+v -> %s", evidence, got)
}
}
}