117 lines
3.4 KiB
Go
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)
|
|
}
|
|
}
|