Files
nostermd-relay/internal/retention/retention_test.go
rgoodall 294616642f
ci / build (push) Successful in 2m3s
ci / image (push) Successful in 1m4s
initial public relay build repo
2026-07-24 13:11:06 -04:00

117 lines
3.4 KiB
Go

package retention
import (
"testing"
"time"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore/slicestore"
)
func mkStore(t *testing.T) *slicestore.SliceStore {
t.Helper()
s := &slicestore.SliceStore{}
if err := s.Init(); err != nil {
t.Fatalf("init: %v", err)
}
return s
}
func save(t *testing.T, s *slicestore.SliceStore, sk nostr.SecretKey, kind nostr.Kind, createdAt nostr.Timestamp) nostr.ID {
t.Helper()
e := nostr.Event{Kind: kind, CreatedAt: createdAt, Tags: nostr.Tags{{"h", "g"}}}
if kind == nostr.KindSimpleGroupChatMessage {
e.Content = "msg"
}
if err := e.Sign(sk); err != nil {
t.Fatalf("sign: %v", err)
}
if err := s.SaveEvent(e); err != nil {
t.Fatalf("save: %v", err)
}
return e.ID
}
func count(s *slicestore.SliceStore, kinds ...nostr.Kind) int {
n := 0
for range s.QueryEvents(nostr.Filter{Kinds: kinds}, 1_000_000) {
n++
}
return n
}
func TestRetentionPrunesOldChatByAge(t *testing.T) {
s := mkStore(t)
sk := nostr.Generate()
now := time.Unix(1_700_000_000, 0)
old := nostr.Timestamp(now.Add(-48 * time.Hour).Unix())
fresh := nostr.Timestamp(now.Add(-1 * time.Hour).Unix())
save(t, s, sk, nostr.KindSimpleGroupChatMessage, old)
save(t, s, sk, nostr.KindSimpleGroupChatMessage, fresh)
deleted := Sweep(s, Config{MaxAge: 24 * time.Hour}, now)
if deleted != 1 {
t.Fatalf("expected 1 pruned, got %d", deleted)
}
if c := count(s, nostr.KindSimpleGroupChatMessage); c != 1 {
t.Fatalf("expected 1 chat remaining, got %d", c)
}
}
func TestRetentionPrunesSurplusByCount(t *testing.T) {
s := mkStore(t)
sk := nostr.Generate()
now := time.Unix(1_700_000_000, 0)
for i := 0; i < 5; i++ {
save(t, s, sk, nostr.KindSimpleGroupChatMessage, nostr.Timestamp(1_700_000_000+int64(i)))
}
deleted := Sweep(s, Config{MaxMessages: 2}, now)
if deleted != 3 {
t.Fatalf("expected 3 pruned, got %d", deleted)
}
if c := count(s, nostr.KindSimpleGroupChatMessage); c != 2 {
t.Fatalf("expected 2 chats remaining, got %d", c)
}
}
func TestRetentionNeverPrunesManagementEvents(t *testing.T) {
s := mkStore(t)
sk := nostr.Generate()
now := time.Unix(1_700_000_000, 0)
ancient := nostr.Timestamp(now.Add(-1000 * time.Hour).Unix())
// Very old management + metadata events must be preserved.
save(t, s, sk, nostr.KindSimpleGroupCreateGroup, ancient)
save(t, s, sk, nostr.KindSimpleGroupPutUser, ancient)
save(t, s, sk, nostr.KindSimpleGroupJoinRequest, ancient)
save(t, s, sk, nostr.KindSimpleGroupMetadata, ancient)
save(t, s, sk, nostr.KindSimpleGroupAdmins, ancient)
save(t, s, sk, nostr.KindSimpleGroupMembers, ancient)
// An old chat that SHOULD be pruned.
save(t, s, sk, nostr.KindSimpleGroupChatMessage, ancient)
deleted := Sweep(s, Config{MaxAge: time.Hour, MaxMessages: 1}, now)
if deleted != 1 {
t.Fatalf("expected only the 1 chat pruned, got %d", deleted)
}
// All 6 management/metadata events survive.
mgmt := count(s,
nostr.KindSimpleGroupCreateGroup, nostr.KindSimpleGroupPutUser,
nostr.KindSimpleGroupJoinRequest, nostr.KindSimpleGroupMetadata,
nostr.KindSimpleGroupAdmins, nostr.KindSimpleGroupMembers)
if mgmt != 6 {
t.Fatalf("management events must never be pruned; have %d/6", mgmt)
}
}
func TestRetentionDisabledIsNoop(t *testing.T) {
s := mkStore(t)
sk := nostr.Generate()
now := time.Unix(1_700_000_000, 0)
save(t, s, sk, nostr.KindSimpleGroupChatMessage, nostr.Timestamp(1))
if d := Sweep(s, Config{}, now); d != 0 {
t.Fatalf("no limits should prune nothing, got %d", d)
}
}