chore: refresh gramsrv public release

This commit is contained in:
A 2026-06-30 14:37:43 +08:00
parent 75cebe8dbf
commit 70b6820474
1274 changed files with 378751 additions and 59919 deletions

View file

@ -0,0 +1,128 @@
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")
}
}