Files
galaxy-game/pkg/transcoder/notification_test.go
T
2026-05-07 00:58:53 +03:00

334 lines
13 KiB
Go

package transcoder
import (
"reflect"
"strings"
"testing"
commonfbs "galaxy/schema/fbs/common"
notificationfbs "galaxy/schema/fbs/notification"
flatbuffers "github.com/google/flatbuffers/go"
"github.com/google/uuid"
)
var (
testNotificationGameID = uuid.MustParse("11111111-1111-1111-1111-111111111111")
testNotificationApplicationID = uuid.MustParse("22222222-2222-2222-2222-222222222222")
testNotificationInviterID = uuid.MustParse("33333333-3333-3333-3333-333333333333")
)
func TestNotificationPayloadRoundTrips(t *testing.T) {
t.Parallel()
tests := []struct {
name string
source any
encode func(any) ([]byte, error)
decode func([]byte) (any, error)
}{
{
name: "lobby invite received",
source: &LobbyInviteReceivedEvent{GameID: testNotificationGameID, InviterUserID: testNotificationInviterID},
encode: func(v any) ([]byte, error) {
return LobbyInviteReceivedEventToPayload(v.(*LobbyInviteReceivedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyInviteReceivedEvent(data) },
},
{
name: "lobby invite revoked",
source: &LobbyInviteRevokedEvent{GameID: testNotificationGameID},
encode: func(v any) ([]byte, error) {
return LobbyInviteRevokedEventToPayload(v.(*LobbyInviteRevokedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyInviteRevokedEvent(data) },
},
{
name: "lobby application submitted",
source: &LobbyApplicationSubmittedEvent{GameID: testNotificationGameID, ApplicationID: testNotificationApplicationID},
encode: func(v any) ([]byte, error) {
return LobbyApplicationSubmittedEventToPayload(v.(*LobbyApplicationSubmittedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyApplicationSubmittedEvent(data) },
},
{
name: "lobby application approved",
source: &LobbyApplicationApprovedEvent{GameID: testNotificationGameID},
encode: func(v any) ([]byte, error) {
return LobbyApplicationApprovedEventToPayload(v.(*LobbyApplicationApprovedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyApplicationApprovedEvent(data) },
},
{
name: "lobby application rejected",
source: &LobbyApplicationRejectedEvent{GameID: testNotificationGameID},
encode: func(v any) ([]byte, error) {
return LobbyApplicationRejectedEventToPayload(v.(*LobbyApplicationRejectedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyApplicationRejectedEvent(data) },
},
{
name: "lobby membership removed",
source: &LobbyMembershipRemovedEvent{Reason: "deleted"},
encode: func(v any) ([]byte, error) {
return LobbyMembershipRemovedEventToPayload(v.(*LobbyMembershipRemovedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyMembershipRemovedEvent(data) },
},
{
name: "lobby membership blocked",
source: &LobbyMembershipBlockedEvent{GameID: testNotificationGameID, Reason: "permanent_blocked"},
encode: func(v any) ([]byte, error) {
return LobbyMembershipBlockedEventToPayload(v.(*LobbyMembershipBlockedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyMembershipBlockedEvent(data) },
},
{
name: "lobby race name registered",
source: &LobbyRaceNameRegisteredEvent{RaceName: "Skylancer"},
encode: func(v any) ([]byte, error) {
return LobbyRaceNameRegisteredEventToPayload(v.(*LobbyRaceNameRegisteredEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyRaceNameRegisteredEvent(data) },
},
{
name: "lobby race name pending",
source: &LobbyRaceNamePendingEvent{RaceName: "Skylancer", ExpiresAt: "2026-05-06T12:00:00Z"},
encode: func(v any) ([]byte, error) {
return LobbyRaceNamePendingEventToPayload(v.(*LobbyRaceNamePendingEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyRaceNamePendingEvent(data) },
},
{
name: "lobby race name expired",
source: &LobbyRaceNameExpiredEvent{RaceName: "Skylancer"},
encode: func(v any) ([]byte, error) {
return LobbyRaceNameExpiredEventToPayload(v.(*LobbyRaceNameExpiredEvent))
},
decode: func(data []byte) (any, error) { return PayloadToLobbyRaceNameExpiredEvent(data) },
},
{
name: "runtime image pull failed",
source: &RuntimeImagePullFailedEvent{GameID: testNotificationGameID, ImageRef: "gcr.io/example:1.0.0"},
encode: func(v any) ([]byte, error) {
return RuntimeImagePullFailedEventToPayload(v.(*RuntimeImagePullFailedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToRuntimeImagePullFailedEvent(data) },
},
{
name: "runtime container start failed",
source: &RuntimeContainerStartFailedEvent{GameID: testNotificationGameID},
encode: func(v any) ([]byte, error) {
return RuntimeContainerStartFailedEventToPayload(v.(*RuntimeContainerStartFailedEvent))
},
decode: func(data []byte) (any, error) { return PayloadToRuntimeContainerStartFailedEvent(data) },
},
{
name: "runtime start config invalid",
source: &RuntimeStartConfigInvalidEvent{GameID: testNotificationGameID, Reason: "missing engine version"},
encode: func(v any) ([]byte, error) {
return RuntimeStartConfigInvalidEventToPayload(v.(*RuntimeStartConfigInvalidEvent))
},
decode: func(data []byte) (any, error) { return PayloadToRuntimeStartConfigInvalidEvent(data) },
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
payload, err := tt.encode(tt.source)
if err != nil {
t.Fatalf("encode payload: %v", err)
}
decoded, err := tt.decode(payload)
if err != nil {
t.Fatalf("decode payload: %v", err)
}
if !reflect.DeepEqual(tt.source, decoded) {
t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", tt.source, decoded)
}
})
}
}
func TestNotificationPayloadEncodersRejectNilInputs(t *testing.T) {
t.Parallel()
tests := []struct {
name string
call func() error
}{
{"lobby invite received", func() error { _, err := LobbyInviteReceivedEventToPayload(nil); return err }},
{"lobby invite revoked", func() error { _, err := LobbyInviteRevokedEventToPayload(nil); return err }},
{"lobby application submitted", func() error { _, err := LobbyApplicationSubmittedEventToPayload(nil); return err }},
{"lobby application approved", func() error { _, err := LobbyApplicationApprovedEventToPayload(nil); return err }},
{"lobby application rejected", func() error { _, err := LobbyApplicationRejectedEventToPayload(nil); return err }},
{"lobby membership removed", func() error { _, err := LobbyMembershipRemovedEventToPayload(nil); return err }},
{"lobby membership blocked", func() error { _, err := LobbyMembershipBlockedEventToPayload(nil); return err }},
{"lobby race name registered", func() error { _, err := LobbyRaceNameRegisteredEventToPayload(nil); return err }},
{"lobby race name pending", func() error { _, err := LobbyRaceNamePendingEventToPayload(nil); return err }},
{"lobby race name expired", func() error { _, err := LobbyRaceNameExpiredEventToPayload(nil); return err }},
{"runtime image pull failed", func() error { _, err := RuntimeImagePullFailedEventToPayload(nil); return err }},
{"runtime container start failed", func() error { _, err := RuntimeContainerStartFailedEventToPayload(nil); return err }},
{"runtime start config invalid", func() error { _, err := RuntimeStartConfigInvalidEventToPayload(nil); return err }},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if err := tt.call(); err == nil {
t.Fatal("expected error")
}
})
}
}
func TestNotificationPayloadDecodersRejectEmptyPayloads(t *testing.T) {
t.Parallel()
tests := []struct {
name string
call func() error
}{
{"lobby invite received", func() error { _, err := PayloadToLobbyInviteReceivedEvent(nil); return err }},
{"lobby invite revoked", func() error { _, err := PayloadToLobbyInviteRevokedEvent(nil); return err }},
{"lobby application submitted", func() error { _, err := PayloadToLobbyApplicationSubmittedEvent(nil); return err }},
{"lobby application approved", func() error { _, err := PayloadToLobbyApplicationApprovedEvent(nil); return err }},
{"lobby application rejected", func() error { _, err := PayloadToLobbyApplicationRejectedEvent(nil); return err }},
{"lobby membership removed", func() error { _, err := PayloadToLobbyMembershipRemovedEvent(nil); return err }},
{"lobby membership blocked", func() error { _, err := PayloadToLobbyMembershipBlockedEvent(nil); return err }},
{"lobby race name registered", func() error { _, err := PayloadToLobbyRaceNameRegisteredEvent(nil); return err }},
{"lobby race name pending", func() error { _, err := PayloadToLobbyRaceNamePendingEvent(nil); return err }},
{"lobby race name expired", func() error { _, err := PayloadToLobbyRaceNameExpiredEvent(nil); return err }},
{"runtime image pull failed", func() error { _, err := PayloadToRuntimeImagePullFailedEvent(nil); return err }},
{"runtime container start failed", func() error { _, err := PayloadToRuntimeContainerStartFailedEvent(nil); return err }},
{"runtime start config invalid", func() error { _, err := PayloadToRuntimeStartConfigInvalidEvent(nil); return err }},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if err := tt.call(); err == nil {
t.Fatal("expected error")
}
})
}
}
func TestNotificationPayloadEncodersRejectMissingUUIDs(t *testing.T) {
t.Parallel()
tests := []struct {
name string
call func() error
want string
}{
{
name: "lobby invite received game_id",
call: func() error { _, err := LobbyInviteReceivedEventToPayload(&LobbyInviteReceivedEvent{InviterUserID: testNotificationInviterID}); return err },
want: "game_id is empty",
},
{
name: "lobby invite received inviter",
call: func() error { _, err := LobbyInviteReceivedEventToPayload(&LobbyInviteReceivedEvent{GameID: testNotificationGameID}); return err },
want: "inviter_user_id is empty",
},
{
name: "lobby application submitted game_id",
call: func() error { _, err := LobbyApplicationSubmittedEventToPayload(&LobbyApplicationSubmittedEvent{ApplicationID: testNotificationApplicationID}); return err },
want: "game_id is empty",
},
{
name: "lobby application submitted application_id",
call: func() error { _, err := LobbyApplicationSubmittedEventToPayload(&LobbyApplicationSubmittedEvent{GameID: testNotificationGameID}); return err },
want: "application_id is empty",
},
{
name: "runtime image pull failed game_id",
call: func() error { _, err := RuntimeImagePullFailedEventToPayload(&RuntimeImagePullFailedEvent{ImageRef: "x"}); return err },
want: "game_id is empty",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.call()
if err == nil {
t.Fatal("expected error")
}
if !strings.Contains(err.Error(), tt.want) {
t.Fatalf("unexpected error: %v", err)
}
})
}
}
func TestNotificationPayloadDecodersRejectMissingUUIDs(t *testing.T) {
t.Parallel()
tests := []struct {
name string
payload func() []byte
decode func([]byte) error
want string
}{
{
name: "lobby invite received game_id",
payload: func() []byte {
builder := flatbuffers.NewBuilder(32)
notificationfbs.LobbyInviteReceivedEventStart(builder)
offset := notificationfbs.LobbyInviteReceivedEventEnd(builder)
notificationfbs.FinishLobbyInviteReceivedEventBuffer(builder, offset)
return builder.FinishedBytes()
},
decode: func(data []byte) error { _, err := PayloadToLobbyInviteReceivedEvent(data); return err },
want: "game_id is missing",
},
{
name: "lobby invite received inviter",
payload: func() []byte {
builder := flatbuffers.NewBuilder(32)
notificationfbs.LobbyInviteReceivedEventStart(builder)
notificationfbs.LobbyInviteReceivedEventAddGameId(builder, commonfbs.CreateUUID(builder, 1, 2))
offset := notificationfbs.LobbyInviteReceivedEventEnd(builder)
notificationfbs.FinishLobbyInviteReceivedEventBuffer(builder, offset)
return builder.FinishedBytes()
},
decode: func(data []byte) error { _, err := PayloadToLobbyInviteReceivedEvent(data); return err },
want: "inviter_user_id is missing",
},
{
name: "lobby application submitted application_id",
payload: func() []byte {
builder := flatbuffers.NewBuilder(32)
notificationfbs.LobbyApplicationSubmittedEventStart(builder)
notificationfbs.LobbyApplicationSubmittedEventAddGameId(builder, commonfbs.CreateUUID(builder, 1, 2))
offset := notificationfbs.LobbyApplicationSubmittedEventEnd(builder)
notificationfbs.FinishLobbyApplicationSubmittedEventBuffer(builder, offset)
return builder.FinishedBytes()
},
decode: func(data []byte) error { _, err := PayloadToLobbyApplicationSubmittedEvent(data); return err },
want: "application_id is missing",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.decode(tt.payload())
if err == nil {
t.Fatal("expected error")
}
if !strings.Contains(err.Error(), tt.want) {
t.Fatalf("unexpected error: %v", err)
}
})
}
}