docs: reorder & testing
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"galaxy/backend/push"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// TestBuildClientPushEventCoversCatalog asserts that every catalog kind
|
||||
// returns a typed FB event (preMarshaledEvent) and that an unknown kind
|
||||
// falls through to the JSON safety net.
|
||||
func TestBuildClientPushEventCoversCatalog(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
gameID := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
applicationID := uuid.MustParse("22222222-2222-2222-2222-222222222222")
|
||||
inviterID := uuid.MustParse("33333333-3333-3333-3333-333333333333")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
kind string
|
||||
payload map[string]any
|
||||
}{
|
||||
{"invite received", KindLobbyInviteReceived, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
"inviter_user_id": inviterID.String(),
|
||||
}},
|
||||
{"invite revoked", KindLobbyInviteRevoked, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
}},
|
||||
{"application submitted", KindLobbyApplicationSubmitted, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
"application_id": applicationID.String(),
|
||||
}},
|
||||
{"application approved", KindLobbyApplicationApproved, map[string]any{"game_id": gameID.String()}},
|
||||
{"application rejected", KindLobbyApplicationRejected, map[string]any{"game_id": gameID.String()}},
|
||||
{"membership removed", KindLobbyMembershipRemoved, map[string]any{"reason": "deleted"}},
|
||||
{"membership blocked", KindLobbyMembershipBlocked, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
"reason": "permanent_blocked",
|
||||
}},
|
||||
{"race name registered", KindLobbyRaceNameRegistered, map[string]any{"race_name": "Skylancer"}},
|
||||
{"race name pending", KindLobbyRaceNamePending, map[string]any{
|
||||
"race_name": "Skylancer",
|
||||
"expires_at": "2026-05-06T12:00:00Z",
|
||||
}},
|
||||
{"race name expired", KindLobbyRaceNameExpired, map[string]any{"race_name": "Skylancer"}},
|
||||
{"runtime image pull failed", KindRuntimeImagePullFailed, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
"image_ref": "gcr.io/example:1.0.0",
|
||||
}},
|
||||
{"runtime container start failed", KindRuntimeContainerStartFailed, map[string]any{"game_id": gameID.String()}},
|
||||
{"runtime start config invalid", KindRuntimeStartConfigInvalid, map[string]any{
|
||||
"game_id": gameID.String(),
|
||||
"reason": "missing engine version",
|
||||
}},
|
||||
}
|
||||
|
||||
seenKinds := map[string]bool{}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
event, err := buildClientPushEvent(tt.kind, tt.payload)
|
||||
if err != nil {
|
||||
t.Fatalf("build %s: %v", tt.kind, err)
|
||||
}
|
||||
if event.Kind() != tt.kind {
|
||||
t.Fatalf("Kind() = %q, want %q", event.Kind(), tt.kind)
|
||||
}
|
||||
bytes, err := event.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal: %v", err)
|
||||
}
|
||||
if len(bytes) == 0 {
|
||||
t.Fatalf("Marshal returned empty bytes")
|
||||
}
|
||||
if _, isJSON := event.(push.JSONEvent); isJSON {
|
||||
t.Fatalf("expected typed FB event for %s, got JSONEvent", tt.kind)
|
||||
}
|
||||
})
|
||||
seenKinds[tt.kind] = true
|
||||
}
|
||||
for _, kind := range SupportedKinds() {
|
||||
if !seenKinds[kind] {
|
||||
t.Errorf("catalog kind %q is not covered by this test", kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildClientPushEventUnknownKindFallsBackToJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
event, err := buildClientPushEvent("unknown.kind", map[string]any{"x": 1})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if _, ok := event.(push.JSONEvent); !ok {
|
||||
t.Fatalf("expected JSONEvent fallback, got %T", event)
|
||||
}
|
||||
if event.Kind() != "unknown.kind" {
|
||||
t.Fatalf("Kind() = %q", event.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildClientPushEventRejectsBrokenPayloads(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
kind string
|
||||
payload map[string]any
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "missing required uuid",
|
||||
kind: KindLobbyApplicationSubmitted,
|
||||
payload: map[string]any{"game_id": uuid.NewString()},
|
||||
want: "application_id is missing",
|
||||
},
|
||||
{
|
||||
name: "non-uuid string",
|
||||
kind: KindLobbyInviteRevoked,
|
||||
payload: map[string]any{"game_id": "not-a-uuid"},
|
||||
want: "is not a uuid",
|
||||
},
|
||||
{
|
||||
name: "uuid not a string",
|
||||
kind: KindLobbyInviteRevoked,
|
||||
payload: map[string]any{"game_id": 42},
|
||||
want: "must be a string",
|
||||
},
|
||||
{
|
||||
name: "missing required string",
|
||||
kind: KindLobbyRaceNameRegistered,
|
||||
payload: map[string]any{},
|
||||
want: "race_name is missing",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := buildClientPushEvent(tt.kind, tt.payload)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.want) {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user