fix: sync collectible upgrade preview pools
This commit is contained in:
parent
eba402946a
commit
de233a4c18
16 changed files with 552 additions and 136 deletions
|
|
@ -798,9 +798,18 @@ func TestPublishStarGiftCollectiblesDryRunThenConfirm(t *testing.T) {
|
|||
svc := NewService(Dependencies{Commands: newMemoryCommandRepo(), Gifts: gifts, Now: fixedNow})
|
||||
base := PublishStarGiftCollectiblesRequest{
|
||||
GiftID: 11, UpgradeStars: 125, SupplyTotal: 100, SlugPrefix: "cake",
|
||||
Models: []StarGiftCollectibleAnimationUpload{{Name: "Ruby", RarityPermille: 1000, FileKey: "model-0", FileName: "ruby.lottie", Data: []byte("model")}},
|
||||
Patterns: []StarGiftCollectibleAnimationUpload{{Name: "Stars", RarityPermille: 1000, FileKey: "pattern-0", FileName: "stars.tgs", Data: []byte("pattern")}},
|
||||
Backdrops: []StarGiftCollectibleBackdropInput{{Name: "Night", BackdropID: 1, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityPermille: 1000}},
|
||||
Models: []StarGiftCollectibleAnimationUpload{
|
||||
{Name: "Ruby", RarityPermille: 500, FileKey: "model-0", FileName: "ruby.lottie", Data: []byte("model")},
|
||||
{Name: "Sapphire", RarityPermille: 500, FileKey: "model-1", FileName: "sapphire.lottie", Data: []byte("model-1")},
|
||||
},
|
||||
Patterns: []StarGiftCollectibleAnimationUpload{
|
||||
{Name: "Stars", RarityPermille: 500, FileKey: "pattern-0", FileName: "stars.tgs", Data: []byte("pattern")},
|
||||
{Name: "Moons", RarityPermille: 500, FileKey: "pattern-1", FileName: "moons.tgs", Data: []byte("pattern-1")},
|
||||
},
|
||||
Backdrops: []StarGiftCollectibleBackdropInput{
|
||||
{Name: "Night", BackdropID: 1, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityPermille: 500},
|
||||
{Name: "Day", BackdropID: 2, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityPermille: 500},
|
||||
},
|
||||
}
|
||||
base.CommandMeta = CommandMeta{CommandID: "dry-collectibles", Actor: "ops", Reason: "pool", DryRun: true}
|
||||
preview, err := svc.PublishStarGiftCollectibles(context.Background(), base)
|
||||
|
|
@ -814,6 +823,45 @@ func TestPublishStarGiftCollectiblesDryRunThenConfirm(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPublishStarGiftCollectiblesRejectsUnsafeClientPreviewPool(t *testing.T) {
|
||||
valid := func() PublishStarGiftCollectiblesRequest {
|
||||
return PublishStarGiftCollectiblesRequest{
|
||||
CommandMeta: CommandMeta{CommandID: "unsafe-pool", Actor: "ops", Reason: "regression", DryRun: true},
|
||||
GiftID: 11, UpgradeStars: 125, SupplyTotal: 100, SlugPrefix: "cake",
|
||||
Models: []StarGiftCollectibleAnimationUpload{
|
||||
{Name: "Ruby", RarityPermille: 500, FileName: "ruby.lottie", Data: []byte("ruby")},
|
||||
{Name: "Sapphire", RarityPermille: 500, FileName: "sapphire.lottie", Data: []byte("sapphire")},
|
||||
},
|
||||
Patterns: []StarGiftCollectibleAnimationUpload{
|
||||
{Name: "Stars", RarityPermille: 500, FileName: "stars.lottie", Data: []byte("stars")},
|
||||
{Name: "Moons", RarityPermille: 500, FileName: "moons.lottie", Data: []byte("moons")},
|
||||
},
|
||||
Backdrops: []StarGiftCollectibleBackdropInput{
|
||||
{Name: "Night", BackdropID: 1, RarityPermille: 500},
|
||||
{Name: "Day", BackdropID: 2, RarityPermille: 500},
|
||||
},
|
||||
}
|
||||
}
|
||||
tests := map[string]func(*PublishStarGiftCollectiblesRequest){
|
||||
"single model": func(req *PublishStarGiftCollectiblesRequest) { req.Models = req.Models[:1] },
|
||||
"single pattern": func(req *PublishStarGiftCollectiblesRequest) { req.Patterns = req.Patterns[:1] },
|
||||
"single backdrop": func(req *PublishStarGiftCollectiblesRequest) { req.Backdrops = req.Backdrops[:1] },
|
||||
"duplicate backdrop id": func(req *PublishStarGiftCollectiblesRequest) {
|
||||
req.Backdrops[1].BackdropID = req.Backdrops[0].BackdropID
|
||||
},
|
||||
}
|
||||
for name, mutate := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
req := valid()
|
||||
mutate(&req)
|
||||
svc := NewService(Dependencies{Commands: newMemoryCommandRepo(), Gifts: &fakeGiftsService{}, Now: fixedNow})
|
||||
if _, err := svc.PublishStarGiftCollectibles(context.Background(), req); !errors.Is(err, domain.ErrStarGiftCollectibleInvalid) {
|
||||
t.Fatalf("err=%v, want ErrStarGiftCollectibleInvalid", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportOfficialStarGiftPreservesCraftedRarityAndPublishesBundle(t *testing.T) {
|
||||
permille := 922
|
||||
source := &fakeOfficialGiftsSource{bundle: officialgifts.Bundle{
|
||||
|
|
@ -828,10 +876,17 @@ func TestImportOfficialStarGiftPreservesCraftedRarityAndPublishesBundle(t *testi
|
|||
Collectible: &officialgifts.CollectibleSet{
|
||||
Models: []officialgifts.Model{
|
||||
{Name: "Regular", DocumentID: 2, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: officialgifts.Document{ID: 2, FileName: "regular.tgs", SHA256: strings.Repeat("b", 64), Data: []byte("regular")}},
|
||||
{Name: "Regular Two", DocumentID: 5, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: officialgifts.Document{ID: 5, FileName: "regular-two.tgs", SHA256: strings.Repeat("e", 64), Data: []byte("regular-two")}},
|
||||
{Name: "Crafted", DocumentID: 3, Crafted: true, Rarity: officialgifts.Rarity{Kind: "legendary"}, Document: officialgifts.Document{ID: 3, FileName: "crafted.tgs", SHA256: strings.Repeat("c", 64), Data: []byte("crafted")}},
|
||||
},
|
||||
Patterns: []officialgifts.Pattern{{Name: "Pattern", DocumentID: 4, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: officialgifts.Document{ID: 4, FileName: "pattern.tgs", SHA256: strings.Repeat("d", 64), Data: []byte("pattern")}}},
|
||||
Backdrops: []officialgifts.Backdrop{{Name: "Black", BackdropID: 0, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}}},
|
||||
Patterns: []officialgifts.Pattern{
|
||||
{Name: "Pattern", DocumentID: 4, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: officialgifts.Document{ID: 4, FileName: "pattern.tgs", SHA256: strings.Repeat("d", 64), Data: []byte("pattern")}},
|
||||
{Name: "Pattern Two", DocumentID: 6, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: officialgifts.Document{ID: 6, FileName: "pattern-two.tgs", SHA256: strings.Repeat("f", 64), Data: []byte("pattern-two")}},
|
||||
},
|
||||
Backdrops: []officialgifts.Backdrop{
|
||||
{Name: "Black", BackdropID: 0, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}},
|
||||
{Name: "White", BackdropID: 1, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
gifts := &fakeGiftsService{}
|
||||
|
|
@ -848,7 +903,7 @@ func TestImportOfficialStarGiftPreservesCraftedRarityAndPublishesBundle(t *testi
|
|||
t.Fatalf("result=%+v err=%v create=%d", result, err, gifts.createCalls)
|
||||
}
|
||||
models := gifts.lastBundle.Collectible.Models
|
||||
if len(models) != 2 || !models[1].Crafted || models[1].RarityKind != domain.StarGiftRarityLegendary || models[1].RarityPermille != 0 ||
|
||||
if len(models) != 3 || !models[2].Crafted || models[2].RarityKind != domain.StarGiftRarityLegendary || models[2].RarityPermille != 0 ||
|
||||
models[0].RarityPermille != 922 || gifts.lastBundle.Collectible.Backdrops[0].BackdropID != 0 {
|
||||
t.Fatalf("imported models=%+v backdrops=%+v", models, gifts.lastBundle.Collectible.Backdrops)
|
||||
}
|
||||
|
|
@ -880,17 +935,18 @@ func TestImportOfficialStarGiftPublishesThroughRealGiftService(t *testing.T) {
|
|||
},
|
||||
BaseDocument: document(1, "gift.json"),
|
||||
Collectible: &officialgifts.CollectibleSet{
|
||||
Models: []officialgifts.Model{{
|
||||
Name: "Model", DocumentID: 2, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille},
|
||||
Document: document(2, "model.json"),
|
||||
}},
|
||||
Patterns: []officialgifts.Pattern{{
|
||||
Name: "Pattern", DocumentID: 3, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille},
|
||||
Document: document(3, "pattern.json"),
|
||||
}},
|
||||
Backdrops: []officialgifts.Backdrop{{
|
||||
Name: "Backdrop", BackdropID: 0, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille},
|
||||
}},
|
||||
Models: []officialgifts.Model{
|
||||
{Name: "Model", DocumentID: 2, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: document(2, "model.json")},
|
||||
{Name: "Model Two", DocumentID: 4, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: document(4, "model-two.json")},
|
||||
},
|
||||
Patterns: []officialgifts.Pattern{
|
||||
{Name: "Pattern", DocumentID: 3, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: document(3, "pattern.json")},
|
||||
{Name: "Pattern Two", DocumentID: 5, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}, Document: document(5, "pattern-two.json")},
|
||||
},
|
||||
Backdrops: []officialgifts.Backdrop{
|
||||
{Name: "Backdrop", BackdropID: 0, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}},
|
||||
{Name: "Backdrop Two", BackdropID: 1, Rarity: officialgifts.Rarity{Kind: "permille", Permille: &permille}},
|
||||
},
|
||||
},
|
||||
}}
|
||||
ctx := context.Background()
|
||||
|
|
@ -911,7 +967,7 @@ func TestImportOfficialStarGiftPublishesThroughRealGiftService(t *testing.T) {
|
|||
t.Fatalf("catalog=%+v err=%v, want one imported gift", catalog, err)
|
||||
}
|
||||
preview, ok, err := giftService.CollectiblePreview(ctx, catalog[0].ID)
|
||||
if err != nil || !ok || len(preview.Models) != 1 || len(preview.Patterns) != 1 {
|
||||
if err != nil || !ok || len(preview.Models) != 2 || len(preview.Patterns) != 2 {
|
||||
t.Fatalf("preview=%+v ok=%v err=%v", preview, ok, err)
|
||||
}
|
||||
model := preview.Models[0].Document
|
||||
|
|
|
|||
|
|
@ -120,11 +120,14 @@ func TestAdminAPIImportStarGiftMultipart(t *testing.T) {
|
|||
func TestAdminAPIPublishStarGiftCollectiblesMultipart(t *testing.T) {
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
metadata := `{"command_id":"pool-1","actor":"ops","reason":"pool","dry_run":true,"upgrade_stars":125,"supply_total":100,"slug_prefix":"cake","models":[{"name":"Ruby","rarity_permille":1000,"sort_order":0,"file_key":"model-0"}],"patterns":[{"name":"Stars","rarity_permille":1000,"sort_order":0,"file_key":"pattern-0"}],"backdrops":[{"name":"Night","backdrop_id":1,"center_color":1122867,"edge_color":2241348,"pattern_color":3359829,"text_color":16777215,"rarity_permille":1000,"sort_order":0}]}`
|
||||
metadata := `{"command_id":"pool-1","actor":"ops","reason":"pool","dry_run":true,"upgrade_stars":125,"supply_total":100,"slug_prefix":"cake","models":[{"name":"Ruby","rarity_permille":500,"sort_order":0,"file_key":"model-0"},{"name":"Sapphire","rarity_permille":500,"sort_order":1,"file_key":"model-1"}],"patterns":[{"name":"Stars","rarity_permille":500,"sort_order":0,"file_key":"pattern-0"},{"name":"Moons","rarity_permille":500,"sort_order":1,"file_key":"pattern-1"}],"backdrops":[{"name":"Night","backdrop_id":1,"center_color":1122867,"edge_color":2241348,"pattern_color":3359829,"text_color":16777215,"rarity_permille":500,"sort_order":0},{"name":"Day","backdrop_id":2,"center_color":11189196,"edge_color":7833753,"pattern_color":14544639,"text_color":1118481,"rarity_permille":500,"sort_order":1}]}`
|
||||
if err := writer.WriteField("metadata", metadata); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for key, name := range map[string]string{"model-0": "ruby.lottie", "pattern-0": "stars.tgs"} {
|
||||
for key, name := range map[string]string{
|
||||
"model-0": "ruby.lottie", "model-1": "sapphire.lottie",
|
||||
"pattern-0": "stars.tgs", "pattern-1": "moons.tgs",
|
||||
} {
|
||||
part, err := writer.CreateFormFile(key, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -146,8 +149,8 @@ func TestAdminAPIPublishStarGiftCollectiblesMultipart(t *testing.T) {
|
|||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if svc.req.GiftID != 11 || len(svc.req.Models) != 1 || svc.req.Models[0].FileName != "ruby.lottie" ||
|
||||
string(svc.req.Patterns[0].Data) != "pattern-0" || len(svc.req.Backdrops) != 1 {
|
||||
if svc.req.GiftID != 11 || len(svc.req.Models) != 2 || svc.req.Models[0].FileName != "ruby.lottie" ||
|
||||
string(svc.req.Patterns[0].Data) != "pattern-0" || len(svc.req.Backdrops) != 2 || svc.req.Backdrops[1].BackdropID != 2 {
|
||||
t.Fatalf("decoded collectible request = %+v", svc.req)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,18 +132,18 @@ func TestCreateCatalogBundleMaterializesPublishableCollectibleDocuments(t *testi
|
|||
},
|
||||
Collectible: &domain.StarGiftCollectibleWrite{
|
||||
UpgradeStars: 100, SupplyTotal: 1000, SlugPrefix: "official-10",
|
||||
Models: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleModel, Name: "Model", RarityKind: domain.StarGiftRarityPermille,
|
||||
RarityPermille: 1000, Animation: &animation,
|
||||
}},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectiblePattern, Name: "Pattern", RarityKind: domain.StarGiftRarityPermille,
|
||||
RarityPermille: 1000, Animation: &animation,
|
||||
}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", RarityKind: domain.StarGiftRarityPermille,
|
||||
RarityPermille: 1000,
|
||||
}},
|
||||
Models: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Model", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500, Animation: &animation},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Model Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500, Animation: &animation},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500, Animation: &animation},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500, Animation: &animation},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 1, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop Two", BackdropID: 2, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
},
|
||||
Actor: "test", CommandID: "official-pool", OfficialGiftID: 10,
|
||||
SourceManifestSHA256: manifestSHA,
|
||||
},
|
||||
|
|
@ -151,7 +151,7 @@ func TestCreateCatalogBundleMaterializesPublishableCollectibleDocuments(t *testi
|
|||
if err != nil {
|
||||
t.Fatalf("create official collectible bundle: %v", err)
|
||||
}
|
||||
if result.Collectible == nil || len(result.Collectible.Models) != 1 || len(result.Collectible.Patterns) != 1 {
|
||||
if result.Collectible == nil || len(result.Collectible.Models) != 2 || len(result.Collectible.Patterns) != 2 {
|
||||
t.Fatalf("collectible result = %+v", result.Collectible)
|
||||
}
|
||||
model := result.Collectible.Models[0].Document
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package domain
|
|||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -139,6 +140,7 @@ func (k StarGiftAttributeRarityKind) Valid() bool {
|
|||
|
||||
// StarGiftCollectibleAttribute 是已发布属性池的一项。RarityKind/RarityPermille
|
||||
// 是客户端展示事实;普通升级把非 crafted 的 permille 值当相对权重,不要求合计为 1000。
|
||||
// 每类仍必须提供至少两个客户端可区分的普通升级属性,否则 TDesktop 的升级滚动无法结束。
|
||||
type StarGiftCollectibleAttribute struct {
|
||||
ID int64
|
||||
CollectibleRevisionID int64
|
||||
|
|
@ -935,7 +937,10 @@ func ValidateStarGiftCollectibleDraft(write StarGiftCollectibleWrite) error {
|
|||
if err := validateStarGiftAttributes(write.Patterns, StarGiftCollectiblePattern, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateStarGiftAttributes(write.Backdrops, StarGiftCollectibleBackdrop, false)
|
||||
if err := validateStarGiftAttributes(write.Backdrops, StarGiftCollectibleBackdrop, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateStarGiftUpgradePreviewPool(write, false)
|
||||
}
|
||||
|
||||
// ValidateStarGiftCollectibleWrite validates a complete publish command. Published pools are
|
||||
|
|
@ -950,7 +955,62 @@ func ValidateStarGiftCollectibleWrite(write StarGiftCollectibleWrite) error {
|
|||
if err := validateStarGiftAttributes(write.Patterns, StarGiftCollectiblePattern, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateStarGiftAttributes(write.Backdrops, StarGiftCollectibleBackdrop, true)
|
||||
if err := validateStarGiftAttributes(write.Backdrops, StarGiftCollectibleBackdrop, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateStarGiftUpgradePreviewPool(write, true)
|
||||
}
|
||||
|
||||
// validateStarGiftUpgradePreviewPool protects the official-client animation contract. The
|
||||
// preview response includes the target attribute plus the published selectable pool; TDesktop
|
||||
// deduplicates models and patterns by document identity and needs a non-target item in every
|
||||
// category before its spinner can transition to the finished state.
|
||||
func validateStarGiftUpgradePreviewPool(write StarGiftCollectibleWrite, requireStoredAsset bool) error {
|
||||
validateAnimated := func(kind StarGiftCollectibleAttributeKind, attributes []StarGiftCollectibleAttribute) error {
|
||||
selectable := 0
|
||||
documents := make(map[int64]struct{}, len(attributes))
|
||||
for _, attribute := range attributes {
|
||||
if attribute.RarityKind != StarGiftRarityPermille || attribute.Crafted {
|
||||
continue
|
||||
}
|
||||
selectable++
|
||||
if requireStoredAsset {
|
||||
if attribute.Document == nil {
|
||||
return fmt.Errorf("%w: %s preview attribute has no document", ErrStarGiftCollectibleInvalid, kind)
|
||||
}
|
||||
documents[attribute.Document.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
if selectable < 2 {
|
||||
return fmt.Errorf("%w: %s preview requires at least two selectable attributes", ErrStarGiftCollectibleInvalid, kind)
|
||||
}
|
||||
if requireStoredAsset && len(documents) < 2 {
|
||||
return fmt.Errorf("%w: %s preview requires at least two distinct documents", ErrStarGiftCollectibleInvalid, kind)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := validateAnimated(StarGiftCollectibleModel, write.Models); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateAnimated(StarGiftCollectiblePattern, write.Patterns); err != nil {
|
||||
return err
|
||||
}
|
||||
seenBackdropIDs := make(map[int]struct{}, len(write.Backdrops))
|
||||
selectableBackdrops := 0
|
||||
for _, attribute := range write.Backdrops {
|
||||
if attribute.RarityKind != StarGiftRarityPermille || attribute.Crafted {
|
||||
continue
|
||||
}
|
||||
selectableBackdrops++
|
||||
if _, exists := seenBackdropIDs[attribute.BackdropID]; exists {
|
||||
return fmt.Errorf("%w: duplicate backdrop_id %d", ErrStarGiftCollectibleInvalid, attribute.BackdropID)
|
||||
}
|
||||
seenBackdropIDs[attribute.BackdropID] = struct{}{}
|
||||
}
|
||||
if selectableBackdrops < 2 {
|
||||
return fmt.Errorf("%w: backdrop preview requires at least two selectable attributes", ErrStarGiftCollectibleInvalid)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateStarGiftAttributes(attributes []StarGiftCollectibleAttribute, kind StarGiftCollectibleAttributeKind, requireStoredAsset bool) error {
|
||||
|
|
|
|||
|
|
@ -48,13 +48,16 @@ func validCollectibleDraft() StarGiftCollectibleWrite {
|
|||
GiftID: 1, UpgradeStars: 25, SupplyTotal: 100, SlugPrefix: "official-1", CommandID: "test",
|
||||
Models: []StarGiftCollectibleAttribute{
|
||||
{Kind: StarGiftCollectibleModel, Name: "Regular", RarityKind: StarGiftRarityPermille, RarityPermille: 922, Animation: animation},
|
||||
{Kind: StarGiftCollectibleModel, Name: "Regular Two", RarityKind: StarGiftRarityPermille, RarityPermille: 78, Animation: animation},
|
||||
{Kind: StarGiftCollectibleModel, Name: "Crafted", RarityKind: StarGiftRarityLegendary, Crafted: true, Animation: animation},
|
||||
},
|
||||
Patterns: []StarGiftCollectibleAttribute{
|
||||
{Kind: StarGiftCollectiblePattern, Name: "Pattern", RarityKind: StarGiftRarityPermille, RarityPermille: 989, Animation: animation},
|
||||
{Kind: StarGiftCollectiblePattern, Name: "Pattern Two", RarityKind: StarGiftRarityPermille, RarityPermille: 11, Animation: animation},
|
||||
},
|
||||
Backdrops: []StarGiftCollectibleAttribute{
|
||||
{Kind: StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 0, RarityKind: StarGiftRarityPermille, RarityPermille: 999},
|
||||
{Kind: StarGiftCollectibleBackdrop, Name: "Backdrop Two", BackdropID: 1, RarityKind: StarGiftRarityPermille, RarityPermille: 1},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -103,15 +106,59 @@ func storedCollectibleWrite() StarGiftCollectibleWrite {
|
|||
}
|
||||
write.Models[i].Blob = &FileBlob{LocationKey: "model"}
|
||||
}
|
||||
write.Patterns[0].Document = &Document{
|
||||
ID: 200, MimeType: "application/x-tgsticker",
|
||||
Attributes: []DocumentAttribute{{Kind: DocAttrCustomEmoji, Alt: "🎁", TextColor: true}},
|
||||
Thumbs: []PhotoSize{{Kind: PhotoSizeKindPath, Type: "j", Bytes: []byte{1}}},
|
||||
for i := range write.Patterns {
|
||||
write.Patterns[i].Document = &Document{
|
||||
ID: int64(200 + i), MimeType: "application/x-tgsticker",
|
||||
Attributes: []DocumentAttribute{{Kind: DocAttrCustomEmoji, Alt: "🎁", TextColor: true}},
|
||||
Thumbs: []PhotoSize{{Kind: PhotoSizeKindPath, Type: "j", Bytes: []byte{1}}},
|
||||
}
|
||||
write.Patterns[i].Blob = &FileBlob{LocationKey: "pattern"}
|
||||
}
|
||||
write.Patterns[0].Blob = &FileBlob{LocationKey: "pattern"}
|
||||
return write
|
||||
}
|
||||
|
||||
func TestValidateStarGiftCollectibleDraftRequiresClientSafePreviewPool(t *testing.T) {
|
||||
tests := map[string]func(*StarGiftCollectibleWrite){
|
||||
"one selectable model": func(write *StarGiftCollectibleWrite) {
|
||||
write.Models = append(write.Models[:1], write.Models[2:]...)
|
||||
},
|
||||
"one selectable pattern": func(write *StarGiftCollectibleWrite) {
|
||||
write.Patterns = write.Patterns[:1]
|
||||
},
|
||||
"one selectable backdrop": func(write *StarGiftCollectibleWrite) {
|
||||
write.Backdrops = write.Backdrops[:1]
|
||||
},
|
||||
"duplicate backdrop id": func(write *StarGiftCollectibleWrite) {
|
||||
write.Backdrops[1].BackdropID = write.Backdrops[0].BackdropID
|
||||
},
|
||||
}
|
||||
for name, mutate := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
write := validCollectibleDraft()
|
||||
mutate(&write)
|
||||
if err := ValidateStarGiftCollectibleDraft(write); !errors.Is(err, ErrStarGiftCollectibleInvalid) {
|
||||
t.Fatalf("err=%v, want ErrStarGiftCollectibleInvalid", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateStarGiftCollectibleWriteRequiresDistinctPreviewDocuments(t *testing.T) {
|
||||
for _, kind := range []StarGiftCollectibleAttributeKind{StarGiftCollectibleModel, StarGiftCollectiblePattern} {
|
||||
t.Run(string(kind), func(t *testing.T) {
|
||||
write := storedCollectibleWrite()
|
||||
if kind == StarGiftCollectibleModel {
|
||||
write.Models[1].Document = write.Models[0].Document
|
||||
} else {
|
||||
write.Patterns[1].Document = write.Patterns[0].Document
|
||||
}
|
||||
if err := ValidateStarGiftCollectibleWrite(write); !errors.Is(err, ErrStarGiftCollectibleInvalid) {
|
||||
t.Fatalf("err=%v, want ErrStarGiftCollectibleInvalid", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateStarGiftCollectibleWriteRequiresExactDocumentRoles(t *testing.T) {
|
||||
if err := ValidateStarGiftCollectibleWrite(storedCollectibleWrite()); err != nil {
|
||||
t.Fatalf("valid stored collectible: %v", err)
|
||||
|
|
|
|||
|
|
@ -594,16 +594,19 @@ func TestStarGiftCollectiblePreviewUpgradeFormUniqueAndServiceProjection(t *test
|
|||
t.Fatalf("gift service = %T", r.deps.Gifts)
|
||||
}
|
||||
model := collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8101, "Aurora")
|
||||
modelTwo := collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8104, "Aurora Two")
|
||||
crafted := collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8103, "Crafted Aurora")
|
||||
crafted.Crafted = true
|
||||
crafted.RarityKind = domain.StarGiftRarityLegendary
|
||||
crafted.RarityPermille = 0
|
||||
pattern := collectibleRPCAttribute(domain.StarGiftCollectiblePattern, 8102, "Orbit")
|
||||
patternTwo := collectibleRPCAttribute(domain.StarGiftCollectiblePattern, 8105, "Orbit Two")
|
||||
backdrop := collectibleRPCAttribute(domain.StarGiftCollectibleBackdrop, 1, "Midnight")
|
||||
backdropTwo := collectibleRPCAttribute(domain.StarGiftCollectibleBackdrop, 2, "Daylight")
|
||||
if _, err := giftService.PublishCollectibleRevision(ctx, domain.StarGiftCollectibleWrite{
|
||||
GiftID: gift.ID, UpgradeStars: 75, SupplyTotal: 500, SlugPrefix: "cake",
|
||||
Models: []domain.StarGiftCollectibleAttribute{model, crafted}, Patterns: []domain.StarGiftCollectibleAttribute{pattern},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{backdrop}, Actor: "test", CommandID: "collectible-rpc",
|
||||
Models: []domain.StarGiftCollectibleAttribute{model, crafted, modelTwo}, Patterns: []domain.StarGiftCollectibleAttribute{pattern, patternTwo},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{backdrop, backdropTwo}, Actor: "test", CommandID: "collectible-rpc",
|
||||
}); err != nil {
|
||||
t.Fatalf("publish collectible pool: %v", err)
|
||||
}
|
||||
|
|
@ -615,11 +618,11 @@ func TestStarGiftCollectiblePreviewUpgradeFormUniqueAndServiceProjection(t *test
|
|||
}
|
||||
|
||||
preview, err := r.onPaymentsGetStarGiftUpgradePreview(ownerCtx, gift.ID)
|
||||
if err != nil || len(preview.SampleAttributes) != 3 {
|
||||
if err != nil || len(preview.SampleAttributes) != 6 {
|
||||
t.Fatalf("upgrade preview = %#v err %v", preview, err)
|
||||
}
|
||||
attributes, err := r.onPaymentsGetStarGiftUpgradeAttributes(ownerCtx, gift.ID)
|
||||
if err != nil || len(attributes.Attributes) != 4 {
|
||||
if err != nil || len(attributes.Attributes) != 7 {
|
||||
t.Fatalf("upgrade attributes = %#v err %v", attributes, err)
|
||||
}
|
||||
craftedTG, ok := attributes.Attributes[1].(*tg.StarGiftAttributeModel)
|
||||
|
|
@ -1004,10 +1007,19 @@ func TestStarGiftChannelSaga(t *testing.T) {
|
|||
giftService := r.deps.Gifts.(*appstargifts.Service)
|
||||
if _, err := giftService.PublishCollectibleRevision(ctx, domain.StarGiftCollectibleWrite{
|
||||
GiftID: gift.ID, UpgradeStars: 75, SupplyTotal: 10, SlugPrefix: "channel-cake",
|
||||
Models: []domain.StarGiftCollectibleAttribute{collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8201, "Aurora")},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{collectibleRPCAttribute(domain.StarGiftCollectiblePattern, 8202, "Orbit")},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{collectibleRPCAttribute(domain.StarGiftCollectibleBackdrop, 2, "Midnight")},
|
||||
Actor: "test", CommandID: "channel-collectible-rpc",
|
||||
Models: []domain.StarGiftCollectibleAttribute{
|
||||
collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8201, "Aurora"),
|
||||
collectibleRPCAttribute(domain.StarGiftCollectibleModel, 8204, "Aurora Two"),
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
collectibleRPCAttribute(domain.StarGiftCollectiblePattern, 8202, "Orbit"),
|
||||
collectibleRPCAttribute(domain.StarGiftCollectiblePattern, 8205, "Orbit Two"),
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
collectibleRPCAttribute(domain.StarGiftCollectibleBackdrop, 2, "Midnight"),
|
||||
collectibleRPCAttribute(domain.StarGiftCollectibleBackdrop, 3, "Daylight"),
|
||||
},
|
||||
Actor: "test", CommandID: "channel-collectible-rpc",
|
||||
}); err != nil {
|
||||
t.Fatalf("publish channel collectible pool: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,24 +43,29 @@ func TestStarGiftCollectibleUpgradeAggregatePostgres(t *testing.T) {
|
|||
Document: collectibleTestDocumentPtr(baseDocumentID+3, "crafted-model.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+3, "crafted-model"), Animation: collectibleTestAnimationPtr("crafted-model.tgs"),
|
||||
OfficialDocumentID: 5100000000000000003,
|
||||
}, {
|
||||
Kind: domain.StarGiftCollectibleModel, Name: "Solar", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 78,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+4, "model-two.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+4, "model-two"), Animation: collectibleTestAnimationPtr("model-two.tgs"),
|
||||
OfficialDocumentID: 5100000000000000004,
|
||||
}},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectiblePattern, Name: "Orbit", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 989,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+2, "pattern.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+2, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs"),
|
||||
}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleBackdrop, Name: "Midnight", BackdropID: 1,
|
||||
CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 999,
|
||||
}},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Orbit", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 989,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+2, "pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+2, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Rings", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 11,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+5, "pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+5, "pattern-two"), Animation: collectibleTestAnimationPtr("pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Midnight", BackdropID: 1, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 999},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Daylight", BackdropID: 2, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1},
|
||||
},
|
||||
Actor: "integration", CommandID: "collectibles-" + suffix,
|
||||
OfficialGiftID: 5170145012310081615, SourceManifestSHA256: make([]byte, 32),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("publish collectible pool: %v", err)
|
||||
}
|
||||
if !poolRevision.Published || poolRevision.Issued != 0 || len(poolRevision.Models) != 2 || len(poolRevision.Patterns) != 1 || len(poolRevision.Backdrops) != 1 ||
|
||||
if !poolRevision.Published || poolRevision.Issued != 0 || len(poolRevision.Models) != 3 || len(poolRevision.Patterns) != 2 || len(poolRevision.Backdrops) != 2 ||
|
||||
!poolRevision.Models[1].Crafted || poolRevision.Models[1].RarityKind != domain.StarGiftRarityLegendary ||
|
||||
poolRevision.Models[1].RarityPermille != 0 || poolRevision.Models[0].OfficialDocumentID != 5100000000000000001 {
|
||||
t.Fatalf("published pool = %+v", poolRevision)
|
||||
|
|
@ -353,21 +358,22 @@ WHERE owner_user_id=$1 AND msg_id=$2`, sender.ID, ownerMessage.ID).Scan(&senderA
|
|||
}
|
||||
soldOutRevision, err := gifts.PublishCollectibleRevision(ctx, domain.StarGiftCollectibleWrite{
|
||||
GiftID: soldOutEntry.Gift.ID, UpgradeStars: 10, SupplyTotal: 1, SlugPrefix: "nova-" + suffix,
|
||||
Models: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleModel, Name: "Nova", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+101, "nova-model.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+101, "nova-model"), Animation: collectibleTestAnimationPtr("nova-model.tgs"),
|
||||
}},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectiblePattern, Name: "Ray", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+102, "nova-pattern.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+102, "nova-pattern"), Animation: collectibleTestAnimationPtr("nova-pattern.tgs"),
|
||||
}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleBackdrop, Name: "Void", BackdropID: 2,
|
||||
CenterColor: 0x101010, EdgeColor: 0x202020, PatternColor: 0x303030, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
}},
|
||||
Models: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Nova", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+101, "nova-model.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+101, "nova-model"), Animation: collectibleTestAnimationPtr("nova-model.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Nova Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+103, "nova-model-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+103, "nova-model-two"), Animation: collectibleTestAnimationPtr("nova-model-two.tgs")},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Ray", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+102, "nova-pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+102, "nova-pattern"), Animation: collectibleTestAnimationPtr("nova-pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Ray Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+104, "nova-pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+104, "nova-pattern-two"), Animation: collectibleTestAnimationPtr("nova-pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Void", BackdropID: 2, CenterColor: 0x101010, EdgeColor: 0x202020, PatternColor: 0x303030, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Light", BackdropID: 3, CenterColor: 0xeeeeee, EdgeColor: 0xcccccc, PatternColor: 0xaaaaaa, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
},
|
||||
Actor: "integration", CommandID: "soldout-pool-" + suffix,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -437,6 +443,65 @@ WHERE owner_user_id=$1 AND msg_id=$2`, sender.ID, ownerMessage.ID).Scan(&senderA
|
|||
}
|
||||
}
|
||||
|
||||
func TestStarGiftCollectiblePreviewActivationGuardPostgres(t *testing.T) {
|
||||
pool := testPool(t)
|
||||
ctx := context.Background()
|
||||
suffix := randomSuffix(t)
|
||||
baseDocumentID := time.Now().UnixNano() & 0x7ffffffffffff000
|
||||
gifts := NewStarGiftStore(pool)
|
||||
entry, err := gifts.CreateCatalogRevision(ctx, domain.StarGiftCatalogWrite{
|
||||
Title: "Unsafe Preview " + suffix, Stars: 10, ConvertStars: 5, Enabled: true,
|
||||
Document: collectibleTestDocument(baseDocumentID, "unsafe-preview.tgs"), Blob: collectibleTestBlob(baseDocumentID, "unsafe-preview"),
|
||||
Animation: collectibleTestAnimation("unsafe-preview.tgs"), Actor: "integration", CommandID: "unsafe-preview-catalog-" + suffix,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create unsafe-preview catalog: %v", err)
|
||||
}
|
||||
var revisionID int64
|
||||
if err := pool.QueryRow(ctx, `
|
||||
INSERT INTO star_gift_collectible_revisions
|
||||
(gift_id, revision, upgrade_stars, supply_total, slug_prefix, status, created_by, command_id)
|
||||
VALUES ($1, 1, 10, 10, $2, 'draft', 'integration', $3)
|
||||
RETURNING id`, entry.Gift.ID, "unsafe-"+suffix, "unsafe-preview-pool-"+suffix).Scan(&revisionID); err != nil {
|
||||
t.Fatalf("insert unsafe-preview revision: %v", err)
|
||||
}
|
||||
animation := collectibleTestAnimation("unsafe-preview-attribute.tgs")
|
||||
if _, err := pool.Exec(ctx, `
|
||||
INSERT INTO star_gift_collectible_models
|
||||
(collectible_revision_id, name, document_id, animation_json, animation_sha256, source_name, source_format,
|
||||
width, height, frame_rate, in_point, out_point, rarity_kind, rarity_permille, crafted, sort_order)
|
||||
VALUES ($1, 'Only Model', $2, $3::jsonb, $4, 'model.tgs', 'tgs', 512, 512, 30, 0, 60, 'permille', 1000, false, 0)`,
|
||||
revisionID, baseDocumentID, string(animation.JSON), animation.SHA256); err != nil {
|
||||
t.Fatalf("insert unsafe-preview model: %v", err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, `
|
||||
INSERT INTO star_gift_collectible_patterns
|
||||
(collectible_revision_id, name, document_id, animation_json, animation_sha256, source_name, source_format,
|
||||
width, height, frame_rate, in_point, out_point, rarity_kind, rarity_permille, sort_order)
|
||||
VALUES ($1, 'Only Pattern', $2, $3::jsonb, $4, 'pattern.tgs', 'tgs', 512, 512, 30, 0, 60, 'permille', 1000, 0)`,
|
||||
revisionID, baseDocumentID, string(animation.JSON), animation.SHA256); err != nil {
|
||||
t.Fatalf("insert unsafe-preview pattern: %v", err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, `
|
||||
INSERT INTO star_gift_collectible_backdrops
|
||||
(collectible_revision_id, name, backdrop_id, center_color, edge_color, pattern_color, text_color,
|
||||
rarity_kind, rarity_permille, sort_order)
|
||||
VALUES ($1, 'Only Backdrop', 1, 1, 2, 3, 4, 'permille', 1000, 0)`, revisionID); err != nil {
|
||||
t.Fatalf("insert unsafe-preview backdrop: %v", err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, `
|
||||
UPDATE star_gift_collectible_revisions SET status='published', published_at=now() WHERE id=$1`, revisionID); err != nil {
|
||||
t.Fatalf("publish unsafe-preview revision directly: %v", err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, `UPDATE star_gift_catalog SET collectible_revision_id=$2 WHERE gift_id=$1`, entry.Gift.ID, revisionID); err == nil {
|
||||
t.Fatal("database activated a collectible preview pool with one client-distinct item per category")
|
||||
}
|
||||
var activeRevisionID *int64
|
||||
if err := pool.QueryRow(ctx, `SELECT collectible_revision_id FROM star_gift_catalog WHERE gift_id=$1`, entry.Gift.ID).Scan(&activeRevisionID); err != nil || activeRevisionID != nil {
|
||||
t.Fatalf("unsafe preview activation pointer=%v err=%v, want null", activeRevisionID, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStarGiftUpgradeWithoutCraftedModelDoesNotAdvertiseCraft(t *testing.T) {
|
||||
pool := testPool(t)
|
||||
ctx := context.Background()
|
||||
|
|
@ -460,27 +525,28 @@ func TestStarGiftUpgradeWithoutCraftedModelDoesNotAdvertiseCraft(t *testing.T) {
|
|||
}
|
||||
revision, err := gifts.PublishCollectibleRevision(ctx, domain.StarGiftCollectibleWrite{
|
||||
GiftID: entry.Gift.ID, UpgradeStars: 100, SupplyTotal: 10, SlugPrefix: "no-craft-" + suffix,
|
||||
Models: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleModel, Name: "Ordinary", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+1, "no-craft-model.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+1, "no-craft-model"), Animation: collectibleTestAnimationPtr("no-craft-model.tgs"),
|
||||
}},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectiblePattern, Name: "Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+2, "no-craft-pattern.tgs"),
|
||||
Blob: collectibleTestBlobPtr(baseDocumentID+2, "no-craft-pattern"), Animation: collectibleTestAnimationPtr("no-craft-pattern.tgs"),
|
||||
}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{
|
||||
Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 1,
|
||||
CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
}},
|
||||
Models: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Ordinary", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+1, "no-craft-model.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+1, "no-craft-model"), Animation: collectibleTestAnimationPtr("no-craft-model.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Ordinary Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+3, "no-craft-model-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "no-craft-model-two"), Animation: collectibleTestAnimationPtr("no-craft-model-two.tgs")},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+2, "no-craft-pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+2, "no-craft-pattern"), Animation: collectibleTestAnimationPtr("no-craft-pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+4, "no-craft-pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+4, "no-craft-pattern-two"), Animation: collectibleTestAnimationPtr("no-craft-pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 1, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop Two", BackdropID: 2, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 500},
|
||||
},
|
||||
Actor: "integration", CommandID: "no-craft-pool-" + suffix,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("publish no-craft pool: %v", err)
|
||||
}
|
||||
if len(revision.Models) != 1 || revision.Models[0].Crafted {
|
||||
if len(revision.Models) != 2 || revision.Models[0].Crafted || revision.Models[1].Crafted {
|
||||
t.Fatalf("no-craft pool models = %+v", revision.Models)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,12 +48,19 @@ func TestStarGiftLifecycleAggregatePostgres(t *testing.T) {
|
|||
Document: collectibleTestDocumentPtr(baseDocumentID+1, "model.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+1, "model"), Animation: collectibleTestAnimationPtr("model.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Crafted", RarityKind: domain.StarGiftRarityLegendary, Crafted: true,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+2, "crafted.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+2, "crafted"), Animation: collectibleTestAnimationPtr("crafted.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Base Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+4, "model-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+4, "model-two"), Animation: collectibleTestAnimationPtr("model-two.tgs")},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Orbit", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Orbit Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+5, "pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+5, "pattern-two"), Animation: collectibleTestAnimationPtr("pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Night", BackdropID: 77, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Day", BackdropID: 78, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectiblePattern, Name: "Orbit", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs")}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectibleBackdrop, Name: "Night", BackdropID: 77,
|
||||
CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000}},
|
||||
Actor: "integration", CommandID: "lifecycle-pool-" + suffix,
|
||||
}); err != nil {
|
||||
t.Fatalf("publish lifecycle pool: %v", err)
|
||||
|
|
@ -760,12 +767,19 @@ func TestStarGiftChannelLifecycleAtomicPostgres(t *testing.T) {
|
|||
Document: collectibleTestDocumentPtr(baseDocumentID+1, "channel-model.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+1, "channel-model"), Animation: collectibleTestAnimationPtr("channel-model.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Channel Crafted", RarityKind: domain.StarGiftRarityLegendary, Crafted: true,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+2, "channel-crafted.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+2, "channel-crafted"), Animation: collectibleTestAnimationPtr("channel-crafted.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Channel Model Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+4, "channel-model-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+4, "channel-model-two"), Animation: collectibleTestAnimationPtr("channel-model-two.tgs")},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Channel Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "channel-pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "channel-pattern"), Animation: collectibleTestAnimationPtr("channel-pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Channel Pattern Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+5, "channel-pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+5, "channel-pattern-two"), Animation: collectibleTestAnimationPtr("channel-pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Channel Backdrop", BackdropID: 88, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Channel Backdrop Two", BackdropID: 89, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectiblePattern, Name: "Channel Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "channel-pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "channel-pattern"), Animation: collectibleTestAnimationPtr("channel-pattern.tgs")}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectibleBackdrop, Name: "Channel Backdrop", BackdropID: 88,
|
||||
CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000}},
|
||||
Actor: "integration", CommandID: "channel-gift-pool-" + suffix,
|
||||
}); err != nil {
|
||||
t.Fatalf("publish channel gift pool: %v", err)
|
||||
|
|
@ -1088,13 +1102,19 @@ func TestStarGiftCraftFailureConsumesThreeInputsPostgres(t *testing.T) {
|
|||
Document: collectibleTestDocumentPtr(baseDocumentID+1, "base.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+1, "base"), Animation: collectibleTestAnimationPtr("base.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Crafted", RarityKind: domain.StarGiftRarityLegendary, Crafted: true,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+2, "crafted.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+2, "crafted"), Animation: collectibleTestAnimationPtr("crafted.tgs")},
|
||||
{Kind: domain.StarGiftCollectibleModel, Name: "Base Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestDocumentPtr(baseDocumentID+4, "base-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+4, "base-two"), Animation: collectibleTestAnimationPtr("base-two.tgs")},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs")},
|
||||
{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern Two", RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+5, "pattern-two.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+5, "pattern-two"), Animation: collectibleTestAnimationPtr("pattern-two.tgs")},
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 88, CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop Two", BackdropID: 89, CenterColor: 0xaabbcc, EdgeColor: 0x778899, PatternColor: 0xddeeff, TextColor: 0x111111, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000},
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectiblePattern, Name: "Pattern",
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000,
|
||||
Document: collectibleTestPatternDocumentPtr(baseDocumentID+3, "pattern.tgs"), Blob: collectibleTestBlobPtr(baseDocumentID+3, "pattern"), Animation: collectibleTestAnimationPtr("pattern.tgs")}},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{{Kind: domain.StarGiftCollectibleBackdrop, Name: "Backdrop", BackdropID: 88,
|
||||
CenterColor: 0x112233, EdgeColor: 0x223344, PatternColor: 0x334455, TextColor: 0xffffff,
|
||||
RarityKind: domain.StarGiftRarityPermille, RarityPermille: 1000}},
|
||||
Actor: "integration", CommandID: "three-input-pool-" + suffix,
|
||||
}); err != nil {
|
||||
t.Fatalf("publish three-input collectible: %v", err)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func TestStarGiftLifecycleMigrationsApply(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("migrate star gift lifecycle schema: %v", err)
|
||||
}
|
||||
if status.Dirty || status.Empty || status.Version != 129 {
|
||||
t.Fatalf("migration status = %+v, want clean version 129", status)
|
||||
if status.Dirty || status.Empty || status.Version != 132 {
|
||||
t.Fatalf("migration status = %+v, want clean version 132", status)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ func TestOfficialStarGiftBundleIsAtomicPostgres(t *testing.T) {
|
|||
attribute := func(kind domain.StarGiftCollectibleAttributeKind, id int64, name string) domain.StarGiftCollectibleAttribute {
|
||||
value := domain.StarGiftCollectibleAttribute{Kind: kind, Name: name, RarityKind: domain.StarGiftRarityPermille, RarityPermille: 918}
|
||||
if kind == domain.StarGiftCollectibleBackdrop {
|
||||
value.BackdropID = 0
|
||||
value.BackdropID = int(id)
|
||||
value.CenterColor, value.EdgeColor, value.PatternColor, value.TextColor = 1, 2, 3, 4
|
||||
return value
|
||||
}
|
||||
|
|
@ -46,10 +46,19 @@ func TestOfficialStarGiftBundleIsAtomicPostgres(t *testing.T) {
|
|||
},
|
||||
Collectible: &domain.StarGiftCollectibleWrite{
|
||||
UpgradeStars: 100, SupplyTotal: 10, SlugPrefix: "official-" + suffix,
|
||||
Models: []domain.StarGiftCollectibleAttribute{attribute(domain.StarGiftCollectibleModel, baseID+1, "model")},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{attribute(domain.StarGiftCollectiblePattern, baseID+2, "pattern")},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{attribute(domain.StarGiftCollectibleBackdrop, 0, "backdrop")},
|
||||
Actor: "integration", CommandID: "official-pool-" + suffix,
|
||||
Models: []domain.StarGiftCollectibleAttribute{
|
||||
attribute(domain.StarGiftCollectibleModel, baseID+1, "model"),
|
||||
attribute(domain.StarGiftCollectibleModel, baseID+3, "model-two"),
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
attribute(domain.StarGiftCollectiblePattern, baseID+2, "pattern"),
|
||||
attribute(domain.StarGiftCollectiblePattern, baseID+4, "pattern-two"),
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
attribute(domain.StarGiftCollectibleBackdrop, 0, "backdrop"),
|
||||
attribute(domain.StarGiftCollectibleBackdrop, 1, "backdrop-two"),
|
||||
},
|
||||
Actor: "integration", CommandID: "official-pool-" + suffix,
|
||||
OfficialGiftID: 5170145012310081615, SourceManifestSHA256: manifestSHA,
|
||||
},
|
||||
}
|
||||
|
|
@ -81,9 +90,15 @@ FROM star_gift_catalog_revisions WHERE id=$1`, result.Catalog.Gift.RevisionID).S
|
|||
attribute(domain.StarGiftCollectibleModel, baseID+101, "duplicate"),
|
||||
attribute(domain.StarGiftCollectibleModel, baseID+102, "duplicate"),
|
||||
},
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{attribute(domain.StarGiftCollectiblePattern, baseID+103, "pattern")},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{attribute(domain.StarGiftCollectibleBackdrop, 0, "backdrop")},
|
||||
Actor: "integration", CommandID: "rollback-pool-" + suffix,
|
||||
Patterns: []domain.StarGiftCollectibleAttribute{
|
||||
attribute(domain.StarGiftCollectiblePattern, baseID+103, "pattern"),
|
||||
attribute(domain.StarGiftCollectiblePattern, baseID+104, "pattern-two"),
|
||||
},
|
||||
Backdrops: []domain.StarGiftCollectibleAttribute{
|
||||
attribute(domain.StarGiftCollectibleBackdrop, 0, "backdrop"),
|
||||
attribute(domain.StarGiftCollectibleBackdrop, 1, "backdrop-two"),
|
||||
},
|
||||
Actor: "integration", CommandID: "rollback-pool-" + suffix,
|
||||
}
|
||||
if _, err := store.CreateCatalogBundle(ctx, failing); !errors.Is(err, domain.ErrStarGiftCollectibleInvalid) {
|
||||
t.Fatalf("failing bundle err=%v", err)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue