Files
lukaszraczylo dded4ec04c Add release infrastructure and complete implementation
- Dockerfile: distroless container for MCP server
- GoReleaser: multi-platform binary and Docker builds with cosign signing
- GitHub Actions: release workflow using shared actions
- Semver config for automatic version calculation
- Persistence layer, content indexing, and improved tool handlers
2026-03-07 18:31:00 +00:00

179 lines
4.1 KiB
Go

package main
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestPersistSaveLoad(t *testing.T) {
dir := t.TempDir()
store1 := NewStore(10000)
if _, err := store1.Add("first item content", "first summary", []string{"tag1"}, 5); err != nil {
t.Fatalf("Add: %v", err)
}
if _, err := store1.Add("second item content", "", []string{"tag2", "tag3"}, 8); err != nil {
t.Fatalf("Add: %v", err)
}
p1, err := NewPersister(dir, store1)
if err != nil {
t.Fatalf("NewPersister: %v", err)
}
errSave := p1.Save()
if errSave != nil {
t.Fatalf("Save: %v", errSave)
}
// Load into a fresh store and verify roundtrip.
store2 := NewStore(10000)
p2, errP2 := NewPersister(dir, store2)
if errP2 != nil {
t.Fatalf("NewPersister (store2): %v", errP2)
}
errLoad := p2.Load()
if errLoad != nil {
t.Fatalf("Load: %v", errLoad)
}
_, _, count1, _ := store1.Status()
_, _, count2, _ := store2.Status()
if count2 != count1 {
t.Fatalf("item count mismatch: got %d, want %d", count2, count1)
}
// Verify individual items survived the roundtrip.
items := store2.Query("", nil, 100)
if len(items) != 2 {
t.Fatalf("expected 2 items from query, got %d", len(items))
}
found := make(map[string]bool)
for _, item := range items {
found[item.Content] = true
if item.Tokens <= 0 {
t.Errorf("item %s has non-positive token count: %d", item.ID, item.Tokens)
}
}
if !found["first item content"] {
t.Error("missing 'first item content' after load")
}
if !found["second item content"] {
t.Error("missing 'second item content' after load")
}
}
func TestPersistAtomicWrite(t *testing.T) {
dir := t.TempDir()
store := NewStore(10000)
if _, err := store.Add("test content", "", nil, 5); err != nil {
t.Fatalf("Add: %v", err)
}
p, err := NewPersister(dir, store)
if err != nil {
t.Fatalf("NewPersister: %v", err)
}
errSave := p.Save()
if errSave != nil {
t.Fatalf("Save: %v", errSave)
}
// state.json should exist.
_, errStat := os.Stat(filepath.Join(dir, "state.json"))
if errStat != nil {
t.Fatalf("state.json missing: %v", errStat)
}
// Temp file should not linger.
_, errTmp := os.Stat(filepath.Join(dir, "state.json.tmp"))
if !os.IsNotExist(errTmp) {
t.Fatal("state.json.tmp should not exist after successful save")
}
}
func TestPersistLoadMissing(t *testing.T) {
dir := t.TempDir()
store := NewStore(10000)
p, err := NewPersister(dir, store)
if err != nil {
t.Fatalf("NewPersister: %v", err)
}
// Loading from a directory with no state.json should succeed (fresh start).
errLoad := p.Load()
if errLoad != nil {
t.Fatalf("Load on missing file should return nil, got: %v", errLoad)
}
_, _, count, _ := store.Status()
if count != 0 {
t.Fatalf("expected 0 items after loading missing file, got %d", count)
}
}
func TestPersistLoadCorrupted(t *testing.T) {
dir := t.TempDir()
// Write garbage to state.json.
errWrite := os.WriteFile(filepath.Join(dir, "state.json"), []byte("{{{garbage"), 0o600)
if errWrite != nil {
t.Fatalf("writing corrupt file: %v", errWrite)
}
store := NewStore(10000)
p, err := NewPersister(dir, store)
if err != nil {
t.Fatalf("NewPersister: %v", err)
}
if p.Load() == nil {
t.Fatal("Load should return error for corrupted file")
}
}
func TestPersistMarkDirty(t *testing.T) {
dir := t.TempDir()
store := NewStore(10000)
p, err := NewPersister(dir, store)
if err != nil {
t.Fatalf("NewPersister: %v", err)
}
// Initially not dirty -- Start + Stop should not create state.json.
p.Start(time.Hour) // long interval so tick won't fire
p.Stop()
_, errStat := os.Stat(filepath.Join(dir, "state.json"))
if !os.IsNotExist(errStat) {
t.Fatal("state.json should not exist when not dirty")
}
// Mark dirty, then Stop should trigger a save.
if _, err := store.Add("dirty item", "", nil, 5); err != nil {
t.Fatalf("Add: %v", err)
}
p2, errP2 := NewPersister(dir, store)
if errP2 != nil {
t.Fatalf("NewPersister: %v", errP2)
}
p2.Start(time.Hour)
p2.MarkDirty()
p2.Stop()
_, errFinal := os.Stat(filepath.Join(dir, "state.json"))
if errFinal != nil {
t.Fatalf("state.json should exist after dirty stop: %v", errFinal)
}
}