hyapp-server/pkg/luckygiftmq/messages_test.go
2026-07-13 21:28:41 +08:00

124 lines
4.0 KiB
Go

package luckygiftmq
import (
"encoding/json"
"testing"
"google.golang.org/protobuf/proto"
luckygifteventsv1 "hyapp.local/api/proto/events/luckygift/v1"
)
func TestLuckyGiftOutboxMessageRoundTrip(t *testing.T) {
envelope := validLuckyGiftEnvelope(t)
body, err := EncodeLuckyGiftOutboxMessage(envelope)
if err != nil {
t.Fatalf("EncodeLuckyGiftOutboxMessage failed: %v", err)
}
decoded, message, err := DecodeLuckyGiftOutboxMessage(body)
if err != nil {
t.Fatalf("DecodeLuckyGiftOutboxMessage failed: %v", err)
}
if !proto.Equal(decoded, envelope) {
t.Fatalf("decoded envelope mismatch: got=%v want=%v", decoded, envelope)
}
if message.MessageType != MessageTypeLuckyGiftOutboxEvent || message.EventType != EventTypeLuckyGiftDrawn || message.DrawID != "draw-1" {
t.Fatalf("decoded wrapper metadata mismatch: %+v", message)
}
}
func TestLuckyGiftOutboxMessageRejectsWrapperEnvelopeDrift(t *testing.T) {
envelope := validLuckyGiftEnvelope(t)
body, err := EncodeLuckyGiftOutboxMessage(envelope)
if err != nil {
t.Fatalf("EncodeLuckyGiftOutboxMessage failed: %v", err)
}
var message LuckyGiftOutboxMessage
if err := json.Unmarshal(body, &message); err != nil {
t.Fatalf("decode wrapper: %v", err)
}
message.DrawID = "draw-other"
tampered, err := json.Marshal(message)
if err != nil {
t.Fatalf("encode tampered wrapper: %v", err)
}
if _, _, err := DecodeLuckyGiftOutboxMessage(tampered); err == nil {
t.Fatal("wrapper/envelope drift must be rejected")
}
}
func TestLuckyGiftOutboxMessageRejectsUnsettledFact(t *testing.T) {
envelope := validLuckyGiftEnvelope(t)
var drawn luckygifteventsv1.LuckyGiftDrawn
if err := proto.Unmarshal(envelope.GetBody(), &drawn); err != nil {
t.Fatalf("decode lucky body: %v", err)
}
drawn.RewardStatus = "pending"
body, err := proto.Marshal(&drawn)
if err != nil {
t.Fatalf("encode pending lucky body: %v", err)
}
envelope.Body = body
if _, err := EncodeLuckyGiftOutboxMessage(envelope); err == nil {
t.Fatal("pending reward must not be published as LuckyGiftDrawn")
}
}
func TestLuckyGiftEventTypeTagAndDisplayBoundary(t *testing.T) {
tag, err := EventTypeTag(EventTypeLuckyGiftDrawn)
if err != nil || tag != TagLuckyGiftDrawn {
t.Fatalf("EventTypeTag result: tag=%q err=%v", tag, err)
}
if _, err := EventTypeTag("LuckyGiftUnknown"); err == nil {
t.Fatal("unsupported lucky gift event type must be rejected")
}
if LuckyGiftDisplayMinMultiplierPPM != 10_000_000 {
t.Fatalf("display threshold=%d, want exact 10x ppm", LuckyGiftDisplayMinMultiplierPPM)
}
}
func validLuckyGiftEnvelope(t *testing.T) *luckygifteventsv1.EventEnvelope {
t.Helper()
const drawCreatedAtMS int64 = 1_783_940_398_274
drawn := &luckygifteventsv1.LuckyGiftDrawn{
DrawId: "draw-1",
CommandId: "command-1",
RoomId: "room-1",
PoolId: "default",
GiftId: "43",
GiftCount: 1,
SenderUserId: 123456,
TargetUserId: 654321,
SenderName: "Lucky User",
SenderAvatar: "https://cdn.example/avatar.png",
SenderDisplayUserId: "123456",
SenderPrettyDisplayUserId: "888888",
VisibleRegionId: 1,
CountryId: 86,
CoinSpent: 100,
RuleVersion: 7,
ExperiencePool: "normal",
SelectedTierId: "normal_50x",
MultiplierPpm: 50_000_000,
BaseRewardCoins: 5_000,
EffectiveRewardCoins: 5_000,
HighMultiplier: true,
RewardStatus: "granted",
WalletTransactionId: "wallet-tx-1",
DrawCreatedAtMs: drawCreatedAtMS,
RewardGrantedAtMs: drawCreatedAtMS + 20,
}
body, err := proto.Marshal(drawn)
if err != nil {
t.Fatalf("marshal lucky body: %v", err)
}
return &luckygifteventsv1.EventEnvelope{
EventId: "lucky_gift_drawn:draw-1",
EventType: EventTypeLuckyGiftDrawn,
AppCode: "lalu",
DrawId: "draw-1",
OccurredAtMs: drawCreatedAtMS,
Body: body,
}
}