2026-05-25 15:45:57 +08:00

110 lines
3.4 KiB
Go

package firstrecharge
import (
"context"
"testing"
"google.golang.org/grpc"
walletv1 "hyapp.local/api/proto/wallet/v1"
"hyapp/pkg/appcode"
domain "hyapp/services/activity-service/internal/domain/firstrecharge"
"hyapp/services/activity-service/internal/testutil/mysqltest"
)
func TestFirstRechargeRewardConsumesRechargeFactWithMySQL(t *testing.T) {
repository := mysqltest.NewRepository(t)
wallet := &fakeWallet{}
svc := New(repository, wallet)
ctx := appcode.WithContext(context.Background(), "lalu")
config, err := svc.UpdateConfig(ctx, domain.Config{
Enabled: true,
UpdatedByAdminID: 90001,
Tiers: []domain.Tier{{
TierCode: "first_100",
TierName: "首冲 100+",
MinCoinAmount: 100,
MaxCoinAmount: 0,
ResourceGroupID: 88001,
Status: domain.TierStatusActive,
}},
})
if err != nil {
t.Fatalf("UpdateConfig failed: %v", err)
}
if len(config.Tiers) != 1 || config.Tiers[0].TierID <= 0 {
t.Fatalf("tier id was not generated: %+v", config.Tiers)
}
event := domain.RechargeEvent{
AppCode: "lalu",
EventID: "evt-recharge-1",
EventType: domain.RechargeEventWalletRecorded,
TransactionID: "wtx-recharge-1",
CommandID: "seller-transfer-1",
UserID: 42001,
RechargeCoinAmount: 500,
RechargeSequence: 1,
RechargeType: domain.RechargeTypeCoinSeller,
OccurredAtMS: 1710000000000,
}
err = svc.ConsumeWalletRechargeEvent(ctx, event)
if err != nil {
t.Fatalf("ConsumeWalletRechargeEvent failed: %v", err)
}
claim, exists, err := repository.GetFirstRechargeRewardClaimByUser(ctx, 42001)
if err != nil {
t.Fatalf("GetFirstRechargeRewardClaimByUser failed: %v", err)
}
if !exists || claim.Status != domain.StatusGranted || claim.ResourceGroupID != 88001 {
t.Fatalf("consume result mismatch: exists=%v claim=%+v", exists, claim)
}
if len(wallet.grants) != 1 || wallet.grants[0].GroupId != 88001 || wallet.grants[0].TargetUserId != 42001 {
t.Fatalf("wallet grant mismatch: %+v", wallet.grants)
}
status, err := svc.GetStatus(ctx, 42001)
if err != nil {
t.Fatalf("GetStatus failed: %v", err)
}
if !status.Rewarded || status.Claim.ClaimID != claim.ClaimID {
t.Fatalf("status should include granted claim: %+v", status)
}
err = svc.ConsumeWalletRechargeEvent(ctx, event)
if err != nil {
t.Fatalf("retry ConsumeWalletRechargeEvent failed: %v", err)
}
if len(wallet.grants) != 1 {
t.Fatalf("retry should be idempotent, grants=%d", len(wallet.grants))
}
event.EventID = "evt-recharge-2"
event.TransactionID = "wtx-recharge-2"
event.CommandID = "seller-transfer-2"
event.RechargeSequence = 2
err = svc.ConsumeWalletRechargeEvent(ctx, event)
if err != nil {
t.Fatalf("second recharge ConsumeWalletRechargeEvent failed: %v", err)
}
if len(wallet.grants) != 1 {
t.Fatalf("second recharge should be ignored, grants=%d", len(wallet.grants))
}
}
type fakeWallet struct {
grants []*walletv1.GrantResourceGroupRequest
}
func (f *fakeWallet) GrantResourceGroup(_ context.Context, req *walletv1.GrantResourceGroupRequest, _ ...grpc.CallOption) (*walletv1.ResourceGrantResponse, error) {
f.grants = append(f.grants, req)
return &walletv1.ResourceGrantResponse{Grant: &walletv1.ResourceGrant{
AppCode: req.GetAppCode(),
GrantId: "grant-first-recharge",
CommandId: req.GetCommandId(),
TargetUserId: req.GetTargetUserId(),
GrantSource: req.GetGrantSource(),
Status: "granted",
}}, nil
}