145 lines
7.5 KiB
Go
145 lines
7.5 KiB
Go
package service
|
|
|
|
import (
|
|
"browser.local/platform/domain"
|
|
"testing"
|
|
)
|
|
|
|
func TestGameGiftGrantFreezesRevisionAndIsIdempotent(t *testing.T) {
|
|
svc, session, player := gameGiftFixture(t, true)
|
|
catalog, err := svc.SaveGameGiftCatalogForSession(session, "server-1", domain.GameGiftCatalogRequest{Name: "月光补给", GameVersion: "0.9.700.90357", Items: []domain.GameGiftItem{{CatalogItemKey: "bandage", Label: "绷带", Quantity: 2}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
revision, err := svc.PublishGameGiftCatalogForSession(session, catalog.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
grant, err := svc.RequestGameGiftGrantForSession(session, "server-1", domain.GameGiftGrantRequest{RevisionID: revision.ID, GamePlayerRecordID: player.ID, Notice: "请查收补给", IdempotencyKey: "gift-once"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
duplicate, err := svc.RequestGameGiftGrantForSession(session, "server-1", domain.GameGiftGrantRequest{RevisionID: revision.ID, GamePlayerRecordID: player.ID, Notice: "changed", IdempotencyKey: "gift-once"})
|
|
if err != nil || duplicate.ID != grant.ID {
|
|
t.Fatalf("idempotency=%+v err=%v", duplicate, err)
|
|
}
|
|
catalog.DraftItems[0].Quantity = 9
|
|
if err = svc.store.GameGiftCatalogs().Update(catalog); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stored, _ := svc.store.GameGiftGrants().Get(grant.ID)
|
|
if stored.Items[0].Quantity != 2 || stored.PlayerDisplayName != "Moon" {
|
|
t.Fatalf("grant was not frozen: %+v", stored)
|
|
}
|
|
if _, err = svc.SaveGameGiftCatalogForSession(session, "server-1", domain.GameGiftCatalogRequest{Name: "坏礼包", GameVersion: "0.9.700.90357", Items: []domain.GameGiftItem{{CatalogItemKey: "not-verified", Label: "bad", Quantity: 1}}}); err == nil {
|
|
t.Fatal("invalid catalog item accepted")
|
|
}
|
|
}
|
|
func TestGameGiftApprovalOfflineAndNotificationFailureAreSafe(t *testing.T) {
|
|
offlineSvc, offlineSession, offlinePlayer := gameGiftFixture(t, false)
|
|
grant := giftGrantForTest(t, offlineSvc, offlineSession, offlinePlayer)
|
|
if _, err := offlineSvc.ApproveGameGiftGrantForSession(offlineSession, grant.ID); err == nil {
|
|
t.Fatal("offline player was dispatched")
|
|
}
|
|
svc, session, player := gameGiftFixture(t, true)
|
|
grant = giftGrantForTest(t, svc, session, player)
|
|
approved, err := svc.ApproveGameGiftGrantForSession(session, grant.ID)
|
|
if err != nil || approved.Status != domain.GameGiftGrantQueued {
|
|
t.Fatalf("approve=%+v err=%v", approved, err)
|
|
}
|
|
claimed, err := svc.claimGameClientBridgeCommands(bridgeComponent(), 1)
|
|
if err != nil || len(claimed) != 1 {
|
|
t.Fatalf("claim delivery=%+v err=%v", claimed, err)
|
|
}
|
|
if _, err = svc.completeGameClientBridgeCommand(bridgeComponent(), domain.GameClientBridgeResultRequest{SessionToken: "session-token", CommandID: claimed[0].ID, FencingToken: claimed[0].Claim.FencingToken, Status: domain.GameClientBridgeResultSucceeded, Summary: "delivered"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
grants, err := svc.ListGameGiftGrantsForSession(session, "server-1")
|
|
if err != nil || grants[0].Status != domain.GameGiftGrantDelivered {
|
|
t.Fatalf("delivery result=%+v err=%v", grants, err)
|
|
}
|
|
claimed, err = svc.claimGameClientBridgeCommands(bridgeComponent(), 1)
|
|
if err != nil || len(claimed) != 1 {
|
|
t.Fatalf("claim notification=%+v err=%v", claimed, err)
|
|
}
|
|
if _, err = svc.completeGameClientBridgeCommand(bridgeComponent(), domain.GameClientBridgeResultRequest{SessionToken: "session-token", CommandID: claimed[0].ID, FencingToken: claimed[0].Claim.FencingToken, Status: domain.GameClientBridgeResultFailed, Summary: "chat unavailable"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
grants, err = svc.ListGameGiftGrantsForSession(session, "server-1")
|
|
if err != nil || grants[0].Status != domain.GameGiftGrantNotificationFailed {
|
|
t.Fatalf("notification failure=%+v err=%v", grants, err)
|
|
}
|
|
commands, _ := svc.store.GameClientBridgeCommands().List(domain.GameClientBridgeCommandFilter{})
|
|
if len(commands) != 2 {
|
|
t.Fatalf("notification failure redelivered item: %d commands", len(commands))
|
|
}
|
|
}
|
|
func TestGameGiftUnknownIsTerminalAndNeverRetried(t *testing.T) {
|
|
svc, session, player := gameGiftFixture(t, true)
|
|
grant := giftGrantForTest(t, svc, session, player)
|
|
approved, err := svc.ApproveGameGiftGrantForSession(session, grant.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
command, _ := svc.store.GameClientBridgeCommands().Get(approved.DeliveryCommandID)
|
|
command.State = domain.GameClientBridgeCommandExpired
|
|
if err = svc.store.GameClientBridgeCommands().Update(command); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
values, err := svc.ListGameGiftGrantsForSession(session, "server-1")
|
|
if err != nil || values[0].Status != domain.GameGiftGrantUnknown {
|
|
t.Fatalf("unknown=%+v err=%v", values, err)
|
|
}
|
|
commands, _ := svc.store.GameClientBridgeCommands().List(domain.GameClientBridgeCommandFilter{})
|
|
if len(commands) != 1 {
|
|
t.Fatalf("unknown result retried: %d", len(commands))
|
|
}
|
|
}
|
|
func gameGiftFixture(t *testing.T, online bool) (*CoreService, string, domain.GamePlayer) {
|
|
t.Helper()
|
|
svc, clock := newGameClientBridgeService(t)
|
|
plugin, _ := svc.store.GamePlugins().Get("game.scum")
|
|
plugin.GameClientBridge.Commands = []domain.GameClientBridgeCommandDeclaration{{Type: domain.SCUMRewardDeliverCommandType, ApprovalLevel: domain.GameClientBridgeApprovalLevelOperator, TimeoutSeconds: 120, MaxPayloadBytes: 4096}, {Type: domain.SCUMGiftNotificationCommandType, ApprovalLevel: domain.GameClientBridgeApprovalLevelOperator, TimeoutSeconds: 60, MaxPayloadBytes: 2048}}
|
|
plugin.LifecycleAssets = append(plugin.LifecycleAssets, domain.PluginAssetFile{Path: "data-packs/scum-db-v57/gift-items.json", Content: `{"gameVersion":"0.9.700.90357","items":[{"key":"bandage","label":"绷带","maximumQuantity":20},{"key":"water-bottle","label":"饮用水","maximumQuantity":10},{"key":"improvised-spear","label":"简易长矛","maximumQuantity":2}]}`})
|
|
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
user := domain.User{ID: "gift-admin", DisplayName: "Gift Admin", Email: "gift@example.test", Roles: []string{"platform-admin"}, Status: domain.UserStatusActive, PasswordHash: "secret", CreatedAt: *clock, UpdatedAt: *clock}
|
|
if err := svc.store.Users().Create(user); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
auth, err := svc.issueAuthSession(user, "test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = svc.store.ServerInstances().Create(domain.ServerInstance{ID: "server-1", PluginID: "game.scum", OwnerUserID: user.ID}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
player := domain.GamePlayer{ID: "gift-player", ServerInstanceID: "server-1", GamePlayerID: "steam-1", DisplayName: "Moon"}
|
|
if err = svc.store.GamePlayers().Create(player); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if online {
|
|
if err = svc.store.GamePlayerSessions().Create(domain.GamePlayerSession{ID: "gift-online", ServerInstanceID: "server-1", GamePlayerRecordID: player.ID, StartedAt: *clock}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return svc, auth.SessionID, player
|
|
}
|
|
func giftGrantForTest(t *testing.T, svc *CoreService, session string, player domain.GamePlayer) domain.GameGiftGrant {
|
|
t.Helper()
|
|
catalog, err := svc.SaveGameGiftCatalogForSession(session, "server-1", domain.GameGiftCatalogRequest{Name: "月光补给", GameVersion: "0.9.700.90357", Items: []domain.GameGiftItem{{CatalogItemKey: "bandage", Label: "绷带", Quantity: 2}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
revision, err := svc.PublishGameGiftCatalogForSession(session, catalog.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
grant, err := svc.RequestGameGiftGrantForSession(session, "server-1", domain.GameGiftGrantRequest{RevisionID: revision.ID, GamePlayerRecordID: player.ID, Notice: "请查收补给", IdempotencyKey: "request-" + catalog.ID})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return grant
|
|
}
|