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

124 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"
)
// TestStarGiftStorePostgres 回归迁移 0011用户收到礼物实例对真实 PG 的 CRUD
// (创建 / keyset 分页 / excludeUnsaved / 隐藏切换 / 转换幂等)。
func TestStarGiftStorePostgres(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
st := NewStarGiftStore(pool)
users := NewUserStore(pool)
suffix := randomSuffix(t)
owner, err := users.Create(ctx, domain.User{AccessHash: 81, Phone: "+1779" + suffix + "51", FirstName: "GiftOwner"})
if err != nil {
t.Fatalf("create owner: %v", err)
}
from, err := users.Create(ctx, domain.User{AccessHash: 82, Phone: "+1779" + suffix + "52", FirstName: "GiftSender"})
if err != nil {
t.Fatalf("create sender: %v", err)
}
ownerPeer := domain.Peer{Type: domain.PeerTypeUser, ID: owner.ID}
t.Cleanup(func() {
_, _ = pool.Exec(ctx, "DELETE FROM peer_star_gifts WHERE owner_peer_id IN ($1, $2)", owner.ID, int64(987654321))
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{owner.ID, from.ID})
})
// 创建三份礼物msg_id 递增)。
for i := 0; i < 3; i++ {
if _, err := st.Create(ctx, domain.SavedStarGift{
Owner: ownerPeer, FromUserID: from.ID, GiftID: 8001, MsgID: 100 + i,
Date: 1700000000 + i, ConvertStars: 50,
}); err != nil {
t.Fatalf("create gift #%d: %v", i, err)
}
}
// keyset 分页:每页 2末页省略游标。
page1, err := st.ListByOwner(ctx, ownerPeer, false, "", 2)
if err != nil {
t.Fatalf("list page1: %v", err)
}
if len(page1.Gifts) != 2 || page1.Count != 3 || page1.NextOffset == "" {
t.Fatalf("page1 = %d count %d next %q, want 2/3/nonempty", len(page1.Gifts), page1.Count, page1.NextOffset)
}
if page1.Gifts[0].MsgID != 102 {
t.Fatalf("page1[0] msg_id = %d, want 102 (newest first)", page1.Gifts[0].MsgID)
}
page2, err := st.ListByOwner(ctx, ownerPeer, false, page1.NextOffset, 2)
if err != nil {
t.Fatalf("list page2: %v", err)
}
if len(page2.Gifts) != 1 || page2.NextOffset != "" {
t.Fatalf("page2 = %d next %q, want 1 + empty (terminal)", len(page2.Gifts), page2.NextOffset)
}
// 隐藏 msg_id=101 → excludeUnsaved 列表少一份。
if ok, err := st.SetUnsaved(ctx, domain.SavedStarGiftRef{Owner: ownerPeer, MsgID: 101}, true); err != nil || !ok {
t.Fatalf("set unsaved = %v err %v", ok, err)
}
shown, err := st.ListByOwner(ctx, ownerPeer, true, "", 100)
if err != nil || len(shown.Gifts) != 2 || shown.Count != 2 {
t.Fatalf("excludeUnsaved = %d count %d err %v, want 2/2", len(shown.Gifts), shown.Count, err)
}
// GetByRef(user msg_id)。
g, found, err := st.GetByRef(ctx, domain.SavedStarGiftRef{Owner: ownerPeer, MsgID: 100})
if err != nil || !found || g.GiftID != 8001 || g.ConvertStars != 50 {
t.Fatalf("get = %+v found %v err %v", g, found, err)
}
// 转换 msg_id=100 → converted从列表消失重复转换被拒。
conv, err := st.MarkConverted(ctx, domain.SavedStarGiftRef{Owner: ownerPeer, MsgID: 100})
if err != nil || conv.ConvertStars != 50 || !conv.Converted {
t.Fatalf("convert = %+v err %v, want ConvertStars 50 converted", conv, err)
}
if _, err := st.MarkConverted(ctx, domain.SavedStarGiftRef{Owner: ownerPeer, MsgID: 100}); !errors.Is(err, domain.ErrStarGiftAlreadyConverted) {
t.Fatalf("double convert err = %v, want ErrStarGiftAlreadyConverted", err)
}
full, _ := st.ListByOwner(ctx, ownerPeer, false, "", 100)
if full.Count != 2 {
t.Fatalf("count after convert = %d, want 2", full.Count)
}
// 转换不存在的礼物。
if _, err := st.MarkConverted(ctx, domain.SavedStarGiftRef{Owner: ownerPeer, MsgID: 999}); !errors.Is(err, domain.ErrStarGiftNotFound) {
t.Fatalf("convert missing err = %v, want ErrStarGiftNotFound", err)
}
// CountByOwner展示在资料 = 非转换、非隐藏100 已转换、101 已隐藏、102 仍展示 → 1。
n, err := st.CountByOwner(ctx, ownerPeer)
if err != nil || n != 1 {
t.Fatalf("CountByOwner = %d err %v, want 1 (100 converted, 101 hidden, 102 shown)", n, err)
}
// 频道礼物用 saved_id 定位,和用户 msg_id 身份键隔离。
channelPeer := domain.Peer{Type: domain.PeerTypeChannel, ID: 987654321}
if _, err := st.Create(ctx, domain.SavedStarGift{
Owner: ownerPeer, FromUserID: from.ID, GiftID: 8001, MsgID: 700,
Date: 1700000100, ConvertStars: 50,
}); err != nil {
t.Fatalf("create user gift with same msg_id namespace: %v", err)
}
channelSavedID, err := st.Create(ctx, domain.SavedStarGift{
Owner: channelPeer, FromUserID: from.ID, GiftID: 8001, MsgID: 0, SavedID: 0,
Date: 1700000101, ConvertStars: 50,
})
if err != nil {
t.Fatalf("create channel gift: %v", err)
}
cg, found, err := st.GetByRef(ctx, domain.SavedStarGiftRef{Owner: channelPeer, SavedID: channelSavedID})
if err != nil || !found || cg.Owner != channelPeer || cg.MsgID != 0 || cg.SavedID != channelSavedID {
t.Fatalf("get channel gift = %+v found %v err %v", cg, found, err)
}
cn, err := st.CountByOwner(ctx, channelPeer)
if err != nil || cn != 1 {
t.Fatalf("channel CountByOwner = %d err %v, want 1", cn, err)
}
}