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

128 lines
4.8 KiB
Go
Raw Permalink 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"
"testing"
"telesrv/internal/domain"
)
// TestNotifySettingsRoundTripPostgres 回归迁移 0005per-scope 通知设置真实持久化
// peer / 类别默认 / 批量 / reset含可空字段=未设置语义。
func TestNotifySettingsRoundTripPostgres(t *testing.T) {
pool := testPool(t)
ctx := context.Background()
store := NewPasswordStore(pool)
users := NewUserStore(pool)
suffix := randomSuffix(t)
u, err := users.Create(ctx, domain.User{AccessHash: 92, Phone: "+1663" + suffix + "01", FirstName: "NotifyOwner"})
if err != nil {
t.Fatalf("create user: %v", err)
}
t.Cleanup(func() {
_, _ = pool.Exec(ctx, "DELETE FROM notify_settings WHERE owner_user_id = $1", u.ID)
_, _ = pool.Exec(ctx, "DELETE FROM users WHERE id = $1", u.ID)
})
peerA := domain.Peer{Type: domain.PeerTypeUser, ID: 7001}
peerB := domain.Peer{Type: domain.PeerTypeChannel, ID: 7002}
scopeA := domain.NotifyScope{Kind: domain.NotifyScopePeer, Peer: peerA}
// not found.
if _, found, err := store.GetNotifySettings(ctx, u.ID, scopeA); err != nil || found {
t.Fatalf("get before save = found %v err %v", found, err)
}
// peer A只设 mute_until + silent其余 nil=未设置)。
mute := 2000000000
silent := true
if err := store.SaveNotifySettings(ctx, u.ID, scopeA, domain.PeerNotifySettings{MuteUntil: &mute, Silent: &silent}); err != nil {
t.Fatalf("save scope A: %v", err)
}
got, found, err := store.GetNotifySettings(ctx, u.ID, scopeA)
if err != nil || !found {
t.Fatalf("get scope A = found %v err %v", found, err)
}
if got.MuteUntil == nil || *got.MuteUntil != mute || got.Silent == nil || !*got.Silent {
t.Fatalf("scope A = %+v, want mute=%d silent=true", got, mute)
}
if got.ShowPreviews != nil || got.StoriesMuted != nil {
t.Fatalf("unset fields must stay nil, got %+v", got)
}
// 类别默认users独立。
usersScope := domain.NotifyScope{Kind: domain.NotifyScopeUsers}
dmute := 100
if err := store.SaveNotifySettings(ctx, u.ID, usersScope, domain.PeerNotifySettings{MuteUntil: &dmute}); err != nil {
t.Fatalf("save users default: %v", err)
}
if g, found, _ := store.GetNotifySettings(ctx, u.ID, usersScope); !found || g.MuteUntil == nil || *g.MuteUntil != dmute {
t.Fatalf("users default = %+v found %v, want mute=%d", g, found, dmute)
}
// peer A 不受类别默认影响。
if g, _, _ := store.GetNotifySettings(ctx, u.ID, scopeA); g.MuteUntil == nil || *g.MuteUntil != mute {
t.Fatalf("scope A polluted by users default: %+v", g)
}
// upsert 覆盖 + 批量mute_until 是 TL int32取接近上限的合法值
mute2 := 2100000000
if err := store.SaveNotifySettings(ctx, u.ID, domain.NotifyScope{Kind: domain.NotifyScopePeer, Peer: peerB}, domain.PeerNotifySettings{MuteUntil: &mute2}); err != nil {
t.Fatalf("save scope B: %v", err)
}
batch, err := store.GetPeerNotifySettings(ctx, u.ID, []domain.Peer{peerA, peerB, {Type: domain.PeerTypeUser, ID: 9999}})
if err != nil {
t.Fatalf("batch: %v", err)
}
if len(batch) != 2 {
t.Fatalf("batch len = %d, want 2 (peerA+peerB, 9999 unset)", len(batch))
}
if a, ok := batch[peerA]; !ok || a.MuteUntil == nil || *a.MuteUntil != mute {
t.Fatalf("batch peerA = %+v ok %v", a, ok)
}
if b, ok := batch[peerB]; !ok || b.MuteUntil == nil || *b.MuteUntil != mute2 {
t.Fatalf("batch peerB = %+v ok %v", b, ok)
}
// AllPeerNotifySettings返全部整-peer 设置peerA+peerB排除类别默认per-user notify 缓存的加载源)。
all, err := store.AllPeerNotifySettings(ctx, u.ID)
if err != nil {
t.Fatalf("all peer notify settings: %v", err)
}
if len(all) != 2 {
t.Fatalf("AllPeerNotifySettings = %d, want 2 (peerA+peerB, 类别默认不计)", len(all))
}
if a, ok := all[peerA]; !ok || a.MuteUntil == nil || *a.MuteUntil != mute {
t.Fatalf("AllPeerNotifySettings peerA = %+v ok %v", a, ok)
}
// ListNotifyExceptions只返 per-peer 非默认peerA+peerB排除类别默认。
exceptions, err := store.ListNotifyExceptions(ctx, u.ID)
if err != nil {
t.Fatalf("list exceptions: %v", err)
}
if len(exceptions) != 2 {
t.Fatalf("exceptions = %d, want 2 (peerA+peerB, 类别默认不计)", len(exceptions))
}
seen := map[domain.Peer]bool{}
for _, ex := range exceptions {
seen[ex.Peer] = true
}
if !seen[peerA] || !seen[peerB] {
t.Fatalf("exceptions peers = %v, want peerA+peerB", seen)
}
// reset 清空全部作用域。
if err := store.ResetNotifySettings(ctx, u.ID); err != nil {
t.Fatalf("reset: %v", err)
}
if ex, _ := store.ListNotifyExceptions(ctx, u.ID); len(ex) != 0 {
t.Fatalf("exceptions after reset = %d, want 0", len(ex))
}
if _, found, _ := store.GetNotifySettings(ctx, u.ID, scopeA); found {
t.Fatalf("scope A must be gone after reset")
}
if _, found, _ := store.GetNotifySettings(ctx, u.ID, usersScope); found {
t.Fatalf("users default must be gone after reset")
}
}