Files
lazyntfy/internal/history/history_test.go
T
ahp 97cc150bf7 feat(history): persist topics and messages in SQLite
Store topics, messages, and small UI preferences in $XDG_DATA_HOME/lazyntfy/history.db. Each topic keeps its newest 1000 messages, expired rows are pruned on startup, and credentials are never written. Saves use a single transaction and prune only when a topic is over the cap.
2026-10-11 12:04:53 +03:30

125 lines
3.1 KiB
Go

package history
import (
"fmt"
"path/filepath"
"testing"
"time"
"lazyntfy/internal/config"
"lazyntfy/internal/store"
)
func TestRoundTrip(t *testing.T) {
path := filepath.Join(t.TempDir(), "history.db")
db, err := Open(path)
if err != nil {
t.Fatal(err)
}
if err := db.SaveTopic(config.Sub{Origin: "https://ntfy.example", Name: "alerts", Display: "Alerts"}); err != nil {
t.Fatal(err)
}
msg := store.Message{
ID: "m1", Topic: "alerts", Time: 20, Title: "Disk", Body: "full",
Tags: []string{"ops"}, Priority: 5, Click: "https://example.com",
Attachment: &store.Attachment{Name: "a.png", URL: "https://example.com/a.png", Size: 4},
}
if err := db.SaveMessage("https://ntfy.example", msg); err != nil {
t.Fatal(err)
}
if err := db.SaveMessage("https://ntfy.example", store.Message{ID: "m0", Topic: "alerts", Time: 10, Body: "older"}); err != nil {
t.Fatal(err)
}
if err := db.SetState("topic", "alerts"); err != nil {
t.Fatal(err)
}
if err := db.Close(); err != nil {
t.Fatal(err)
}
db, err = Open(path)
if err != nil {
t.Fatal(err)
}
defer db.Close()
topics, err := db.Topics()
if err != nil || len(topics) != 1 || topics[0].Display != "Alerts" || topics[0].Auth.Token != "" {
t.Fatalf("%v %+v", err, topics)
}
got, err := db.Messages("alerts", 10)
if err != nil || len(got) != 2 || got[0].ID != "m1" || got[0].Tags[0] != "ops" || got[0].Attachment.Name != "a.png" {
t.Fatalf("%v %+v", err, got)
}
if name, ok := db.State("topic"); !ok || name != "alerts" {
t.Fatalf("state %q %v", name, ok)
}
if err := db.DeleteMessage("m0"); err != nil {
t.Fatal(err)
}
if err := db.ClearTopic("alerts"); err != nil {
t.Fatal(err)
}
left, err := db.Messages("alerts", 10)
if err != nil || len(left) != 0 {
t.Fatalf("%v %+v", err, left)
}
}
func TestPruneExpiredOnOpen(t *testing.T) {
path := filepath.Join(t.TempDir(), "history.db")
db, err := Open(path)
if err != nil {
t.Fatal(err)
}
now := time.Now().Unix()
for _, m := range []store.Message{
{ID: "live", Topic: "t", Time: 1},
{ID: "gone", Topic: "t", Time: 2, Expires: now - 60},
{ID: "later", Topic: "t", Time: 3, Expires: now + 3600},
} {
if err := db.SaveMessage("o", m); err != nil {
t.Fatal(err)
}
}
if err := db.Close(); err != nil {
t.Fatal(err)
}
db, err = Open(path)
if err != nil {
t.Fatal(err)
}
defer db.Close()
got, err := db.Messages("t", 10)
if err != nil {
t.Fatal(err)
}
if len(got) != 2 || got[0].ID != "later" || got[1].ID != "live" {
t.Fatalf("kept %+v", got)
}
}
func TestTopicCapKeepsNewest(t *testing.T) {
db, err := Open(filepath.Join(t.TempDir(), "history.db"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
for i := 0; i < maxPerTopic+5; i++ {
msg := store.Message{ID: fmt.Sprintf("m%d", i), Topic: "t", Time: int64(i)}
if err := db.SaveMessage("o", msg); err != nil {
t.Fatal(err)
}
}
got, err := db.Messages("t", maxPerTopic+100)
if err != nil {
t.Fatal(err)
}
if len(got) != maxPerTopic {
t.Fatalf("kept %d, want %d", len(got), maxPerTopic)
}
if got[0].ID != fmt.Sprintf("m%d", maxPerTopic+4) {
t.Fatalf("newest is %s", got[0].ID)
}
}