168 lines
6.2 KiB
Go
168 lines
6.2 KiB
Go
package notification
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"galaxy/notification/internal/api/intentstream"
|
|
"galaxy/notificationintent"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNotificationProducerIntegrationDocsStayInSync(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
readme := loadTextFile(t, "README.md")
|
|
runtimeDoc := loadTextFile(t, filepath.Join("docs", "runtime.md"))
|
|
examplesDoc := loadTextFile(t, filepath.Join("docs", "examples.md"))
|
|
docsIndex := loadTextFile(t, filepath.Join("docs", "README.md"))
|
|
architecture := loadTextFile(t, filepath.Join("..", "ARCHITECTURE.md"))
|
|
geoProfileReadme := loadTextFile(t, filepath.Join("..", "geoprofile", "README.md"))
|
|
|
|
require.Contains(t, docsIndex, "- [Runtime and components](runtime.md)")
|
|
require.Contains(t, docsIndex, "- [Configuration and contract examples](examples.md)")
|
|
|
|
for _, content := range []string{readme, runtimeDoc, architecture, geoProfileReadme} {
|
|
normalizedContent := normalizeWhitespace(content)
|
|
require.Contains(t, normalizedContent, normalizeWhitespace("`galaxy/notificationintent`"))
|
|
require.Contains(t, normalizedContent, normalizeWhitespace("notification degradation"))
|
|
}
|
|
require.Contains(t, normalizeWhitespace(readme), normalizeWhitespace("producer publication uses plain `XADD` without stream trimming or hidden helper retries"))
|
|
require.Contains(t, normalizeWhitespace(examplesDoc), normalizeWhitespace("redis-cli XADD notification:intents"))
|
|
}
|
|
|
|
func TestNotificationProducerIntentsDecodeThroughServiceContract(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, original := range compatibleProducerIntents(t) {
|
|
original := original
|
|
t.Run(original.NotificationType.String()+"/"+original.AudienceKind.String(), func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
values, err := original.Values()
|
|
require.NoError(t, err)
|
|
|
|
decoded, err := intentstream.DecodeIntent(values)
|
|
require.NoError(t, err)
|
|
require.Equal(t, original.NotificationType, decoded.NotificationType)
|
|
require.Equal(t, original.Producer, decoded.Producer)
|
|
require.Equal(t, original.AudienceKind, decoded.AudienceKind)
|
|
require.Equal(t, original.RecipientUserIDs, decoded.RecipientUserIDs)
|
|
require.Equal(t, original.IdempotencyKey, decoded.IdempotencyKey)
|
|
require.Equal(t, original.OccurredAt, decoded.OccurredAt)
|
|
require.JSONEq(t, original.PayloadJSON, decoded.PayloadJSON)
|
|
})
|
|
}
|
|
}
|
|
|
|
func compatibleProducerIntents(t *testing.T) []notificationintent.Intent {
|
|
t.Helper()
|
|
|
|
metadata := notificationintent.Metadata{
|
|
IdempotencyKey: "idempotency-1",
|
|
OccurredAt: time.UnixMilli(1775121700000),
|
|
}
|
|
|
|
builders := []func() (notificationintent.Intent, error){
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewGeoReviewRecommendedIntent(metadata, notificationintent.GeoReviewRecommendedPayload{
|
|
UserID: "user-1",
|
|
UserEmail: "pilot@example.com",
|
|
ObservedCountry: "DE",
|
|
UsualConnectionCountry: "PL",
|
|
ReviewReason: "country_mismatch",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewGameTurnReadyIntent(metadata, []string{"user-1", "user-2"}, notificationintent.GameTurnReadyPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
TurnNumber: 54,
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewGameFinishedIntent(metadata, []string{"user-1", "user-2"}, notificationintent.GameFinishedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
FinalTurnNumber: 55,
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewGameGenerationFailedIntent(metadata, notificationintent.GameGenerationFailedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
FailureReason: "engine_timeout",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyRuntimePausedAfterStartIntent(metadata, notificationintent.LobbyRuntimePausedAfterStartPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewPrivateLobbyApplicationSubmittedIntent(metadata, "owner-1", notificationintent.LobbyApplicationSubmittedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
ApplicantUserID: "user-2",
|
|
ApplicantName: "Nova Pilot",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewPublicLobbyApplicationSubmittedIntent(metadata, notificationintent.LobbyApplicationSubmittedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
ApplicantUserID: "user-2",
|
|
ApplicantName: "Nova Pilot",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyMembershipApprovedIntent(metadata, "applicant-1", notificationintent.LobbyMembershipApprovedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyMembershipRejectedIntent(metadata, "applicant-1", notificationintent.LobbyMembershipRejectedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyInviteCreatedIntent(metadata, "invited-1", notificationintent.LobbyInviteCreatedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
InviterUserID: "owner-1",
|
|
InviterName: "Owner Pilot",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyInviteRedeemedIntent(metadata, "owner-1", notificationintent.LobbyInviteRedeemedPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
InviteeUserID: "invitee-1",
|
|
InviteeName: "Nova Pilot",
|
|
})
|
|
},
|
|
func() (notificationintent.Intent, error) {
|
|
return notificationintent.NewLobbyInviteExpiredIntent(metadata, "owner-1", notificationintent.LobbyInviteExpiredPayload{
|
|
GameID: "game-1",
|
|
GameName: "Nebula Clash",
|
|
InviteeUserID: "invitee-1",
|
|
InviteeName: "Nova Pilot",
|
|
})
|
|
},
|
|
}
|
|
|
|
intents := make([]notificationintent.Intent, 0, len(builders))
|
|
for _, build := range builders {
|
|
intent, err := build()
|
|
require.NoError(t, err)
|
|
intents = append(intents, intent)
|
|
}
|
|
|
|
return intents
|
|
}
|