334 lines
13 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|