112 lines
5.6 KiB
Go
112 lines
5.6 KiB
Go
package app
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
"time"
|
||
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/pkg/walletmq"
|
||
messageservice "hyapp/services/activity-service/internal/service/message"
|
||
"hyapp/services/activity-service/internal/testutil/mysqltest"
|
||
)
|
||
|
||
func TestVIPRebateAvailableEventFromWalletMessage(t *testing.T) {
|
||
body := vipRebateWalletMessage(t, "VipDailyCoinRebateAvailable", 42, `{
|
||
"rebate_id":"viprebate_fami_2027-01-15_42",
|
||
"user_id":42,
|
||
"task_day":"2027-01-15",
|
||
"vip_level":9,
|
||
"vip_name":"VIP9",
|
||
"coin_amount":100000,
|
||
"available_at_ms":1800000000000,
|
||
"expires_at_ms":1800086400000,
|
||
"config_version":7,
|
||
"created_at_ms":1800000000100
|
||
}`)
|
||
event, ok, err := vipRebateAvailableEventFromWalletMessage(body)
|
||
if err != nil || !ok {
|
||
t.Fatalf("parse VIP rebate event failed: ok=%v event=%+v err=%v", ok, event, err)
|
||
}
|
||
if event.AppCode != "fami" || event.EventID != "wev-vip-rebate" || event.RebateID != "viprebate_fami_2027-01-15_42" || event.UserID != 42 || event.TaskDay != "2027-01-15" || event.VIPLevel != 9 || event.CoinAmount != 100000 || event.ExpiresAtMS != 1800086400000 || event.ConfigVersion != 7 {
|
||
t.Fatalf("VIP rebate event mismatch: %+v", event)
|
||
}
|
||
}
|
||
|
||
func TestVIPRebateWalletEventSkipsOtherFactsAndRejectsCorruptTarget(t *testing.T) {
|
||
other := vipRebateWalletMessage(t, "WalletRechargeRecorded", 42, `{}`)
|
||
if event, ok, err := vipRebateAvailableEventFromWalletMessage(other); err != nil || ok || event.EventID != "" {
|
||
t.Fatalf("non-target event should be acknowledged: ok=%v event=%+v err=%v", ok, event, err)
|
||
}
|
||
corrupt := vipRebateWalletMessage(t, "VipDailyCoinRebateAvailable", 42, `{"rebate_id":"r1","user_id":99}`)
|
||
if _, ok, err := vipRebateAvailableEventFromWalletMessage(corrupt); err == nil || ok {
|
||
t.Fatalf("corrupt target event must fail for MQ retry: ok=%v err=%v", ok, err)
|
||
}
|
||
}
|
||
|
||
func TestVIPRebateWalletEventCreatesOneIdempotentSystemNotice(t *testing.T) {
|
||
ctx := appcode.WithContext(context.Background(), "fami")
|
||
repository := mysqltest.NewRepository(t)
|
||
service := messageservice.New(messageservice.Config{NodeID: "activity-test"}, repository)
|
||
service.SetClock(func() time.Time { return time.UnixMilli(1800000000200) })
|
||
event := vipRebateAvailableEvent{
|
||
AppCode: "fami", EventID: "wev-vip-rebate", RebateID: "viprebate_fami_2027-01-15_42",
|
||
UserID: 42, TaskDay: "2027-01-15", VIPLevel: 9, VIPName: "VIP9", CoinAmount: 100000,
|
||
AvailableAtMS: 1800000000000, ExpiresAtMS: 1800086400000, ConfigVersion: 7, CreatedAtMS: 1800000000100,
|
||
}
|
||
if err := createVIPRebateSystemNotice(ctx, service, event); err != nil {
|
||
t.Fatalf("create system notice failed: %v", err)
|
||
}
|
||
if err := createVIPRebateSystemNotice(ctx, service, event); err != nil {
|
||
t.Fatalf("duplicate system notice should be idempotent: %v", err)
|
||
}
|
||
items, _, err := service.ListInboxMessages(ctx, 42, "system", 20, "")
|
||
if err != nil || len(items) != 1 {
|
||
t.Fatalf("system inbox mismatch: items=%+v err=%v", items, err)
|
||
}
|
||
item := items[0]
|
||
wantSummary := "Your daily VIP cashback of 100000 coins is ready. Claim it before it expires."
|
||
if item.Title != "VIP Coin Cashback" || item.Summary != wantSummary || item.Body != wantSummary || item.TemplateVersion != "v2" || item.AggregateID != event.RebateID || item.ExpireAtMS != event.ExpiresAtMS || len(item.Actions) != 1 {
|
||
t.Fatalf("VIP rebate notice mismatch: %+v", item)
|
||
}
|
||
action := item.Actions[0]
|
||
if action.Action != "claim" || action.Label != "Claim" || action.Style != "primary" || action.API.Method != "POST" || action.API.Path != "/api/v1/vip/coin-rebates/viprebate_fami_2027-01-15_42/claim" || action.API.Body == nil {
|
||
t.Fatalf("VIP rebate action mismatch: %+v", action)
|
||
}
|
||
|
||
// 当天部署前已经落库的 v1 中文消息仍在有效窗口内;列表读取必须立即投影为同一英文文案。
|
||
legacyActionParam := `{"coin_amount":88,"rebate_id":"viprebate_fami_2027-01-15_43"}`
|
||
if _, err := service.CreateSystemNotice(ctx, messageservice.NoticeCommand{
|
||
TargetUserID: 43, Producer: "wallet-service", ProducerEventID: "wev-vip-rebate-legacy",
|
||
TemplateID: "vip_daily_coin_rebate_available", TemplateVersion: "v1",
|
||
Title: "VIP金币返现", Summary: "尊敬的VIP用户,平台今日返现88金币,请及时领取。",
|
||
Body: "尊敬的VIP用户,平台今日返现88金币,请及时领取。", ActionType: "vip_coin_rebate_claim",
|
||
ActionParam: legacyActionParam, SentAtMS: event.AvailableAtMS, ExpireAtMS: event.ExpiresAtMS,
|
||
}); err != nil {
|
||
t.Fatalf("create legacy system notice failed: %v", err)
|
||
}
|
||
legacyItems, _, err := service.ListInboxMessages(ctx, 43, "system", 20, "")
|
||
if err != nil || len(legacyItems) != 1 || legacyItems[0].Title != "VIP Coin Cashback" || legacyItems[0].Summary != "Your daily VIP cashback of 88 coins is ready. Claim it before it expires." || legacyItems[0].Body != legacyItems[0].Summary || legacyItems[0].ActionType != "" || len(legacyItems[0].Actions) != 1 || legacyItems[0].Actions[0].Label != "Claim" {
|
||
t.Fatalf("legacy VIP rebate notice must return English copy: items=%+v err=%v", legacyItems, err)
|
||
}
|
||
}
|
||
|
||
func vipRebateWalletMessage(t *testing.T, eventType string, userID int64, payload string) []byte {
|
||
t.Helper()
|
||
body, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{
|
||
AppCode: "fami",
|
||
EventID: "wev-vip-rebate",
|
||
EventType: eventType,
|
||
TransactionID: "viprebate_fami_2027-01-15_42",
|
||
CommandID: "vip-rebate-generate:fami:2027-01-15:42",
|
||
UserID: userID,
|
||
AssetType: "COIN",
|
||
PayloadJSON: payload,
|
||
OccurredAtMS: 1800000000100,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("encode wallet outbox message: %v", err)
|
||
}
|
||
return body
|
||
}
|