owpengram-server/internal/store/postgres/paid_reaction_integration_test.go

129 lines
5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package postgres
import (
"context"
"errors"
"testing"
"telesrv/internal/domain"
)
// TestChannelPaidReactionPostgres 回归迁移 0010广播频道付费 reaction 对真实 PG 的累计 +
// 聚合(总星数 / viewer 自身 / top reactors 降序 / 同 reactor 多次累加)。
func TestChannelPaidReactionPostgres(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
suffix := randomSuffix(t)
users := NewUserStore(pool)
owner, err := users.Create(ctx, domain.User{AccessHash: 521, Phone: "+1778" + suffix + "41", FirstName: "PaidRxOwner"})
if err != nil {
t.Fatalf("create owner: %v", err)
}
member, err := users.Create(ctx, domain.User{AccessHash: 522, Phone: "+1778" + suffix + "42", FirstName: "PaidRxMember"})
if err != nil {
t.Fatalf("create member: %v", err)
}
var channelID int64
t.Cleanup(func() {
if channelID != 0 {
_, _ = pool.Exec(ctx, "DELETE FROM channel_message_paid_reactions WHERE channel_id = $1", channelID)
_, _ = pool.Exec(ctx, "DELETE FROM channels WHERE id = $1", channelID)
}
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, member.ID})
})
channels := NewChannelStore(pool)
created, err := channels.CreateChannel(ctx, domain.CreateChannelRequest{
CreatorUserID: owner.ID,
Title: "Paid Reaction " + suffix,
Broadcast: true,
MemberUserIDs: []int64{member.ID},
Date: 1700000400,
})
if err != nil {
t.Fatalf("create broadcast channel: %v", err)
}
channelID = created.Channel.ID
sent, err := channels.SendChannelMessage(ctx, domain.SendChannelMessageRequest{
UserID: owner.ID,
ChannelID: channelID,
RandomID: 9401,
Message: "paid reaction target",
Date: 1700000401,
})
if err != nil {
t.Fatalf("send message: %v", err)
}
msgID := sent.Message.ID
// owner 投 100。
res, err := channels.AddChannelMessagePaidReaction(ctx, domain.SendChannelPaidReactionRequest{
UserID: owner.ID, ChannelID: channelID, MessageID: msgID, Stars: 100, Date: 1700000402,
})
if err != nil {
t.Fatalf("owner paid reaction: %v", err)
}
if res.Paid.TotalStars != 100 || res.Paid.MyStars != 100 {
t.Fatalf("after owner 100 = total %d my %d, want 100/100", res.Paid.TotalStars, res.Paid.MyStars)
}
// member 投 250 → 总 350member 视角 my=250top reactors 降序 member(250)/owner(100)。
res, err = channels.AddChannelMessagePaidReaction(ctx, domain.SendChannelPaidReactionRequest{
UserID: member.ID, ChannelID: channelID, MessageID: msgID, Stars: 250, Date: 1700000403,
})
if err != nil {
t.Fatalf("member paid reaction: %v", err)
}
if res.Paid.TotalStars != 350 || res.Paid.MyStars != 250 {
t.Fatalf("after member 250 = total %d my %d, want 350/250", res.Paid.TotalStars, res.Paid.MyStars)
}
if len(res.Paid.TopReactors) != 2 || res.Paid.TopReactors[0].Stars != 250 || !res.Paid.TopReactors[0].My || res.Paid.TopReactors[1].Stars != 100 {
t.Fatalf("top reactors = %+v, want member(250,My)/owner(100)", res.Paid.TopReactors)
}
// owner 再投 50 → 累加到 150总 400。
res, err = channels.AddChannelMessagePaidReaction(ctx, domain.SendChannelPaidReactionRequest{
UserID: owner.ID, ChannelID: channelID, MessageID: msgID, Stars: 50, Date: 1700000404,
})
if err != nil {
t.Fatalf("owner re-invest: %v", err)
}
if res.Paid.TotalStars != 400 || res.Paid.MyStars != 150 {
t.Fatalf("after owner +50 = total %d my %d, want 400/150 (accumulated)", res.Paid.TotalStars, res.Paid.MyStars)
}
// 关键回归读路径修复fresh 读回该消息必须携带付费 reaction不止实时推送
// owner 视角Paid.TotalStars=400, MyStars=150。
read, err := channels.GetChannelMessageReactions(ctx, domain.ChannelMessageReactionsRequest{
UserID: owner.ID, ChannelID: channelID, IDs: []int{msgID},
})
if err != nil {
t.Fatalf("get message reactions: %v", err)
}
if len(read.Messages) != 1 || read.Messages[0].Reactions == nil || read.Messages[0].Reactions.Paid == nil {
t.Fatalf("fresh read messages=%d reactions/paid missing: %+v", len(read.Messages), read.Messages)
}
paid := read.Messages[0].Reactions.Paid
if paid.TotalStars != 400 || paid.MyStars != 150 {
t.Fatalf("fresh read paid = total %d my %d, want 400/150 (读路径须回显付费 reaction)", paid.TotalStars, paid.MyStars)
}
// member 视角读同一条MyStars=250、TopReactors 含 member 自己带 My。
readMember, err := channels.GetChannelMessageReactions(ctx, domain.ChannelMessageReactionsRequest{
UserID: member.ID, ChannelID: channelID, IDs: []int{msgID},
})
if err != nil {
t.Fatalf("get message reactions (member): %v", err)
}
mp := readMember.Messages[0].Reactions.Paid
if mp == nil || mp.TotalStars != 400 || mp.MyStars != 250 {
t.Fatalf("member fresh read paid = %+v, want total 400 my 250", mp)
}
// 非法星数被拒。
if _, err := channels.AddChannelMessagePaidReaction(ctx, domain.SendChannelPaidReactionRequest{
UserID: owner.ID, ChannelID: channelID, MessageID: msgID, Stars: 0, Date: 1700000405,
}); !errors.Is(err, domain.ErrChannelInvalid) {
t.Fatalf("zero-stars err = %v, want ErrChannelInvalid", err)
}
}