This repository has been archived on 2026-03-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
oubliette/internal/storage/retention_test.go
Torjus Håkestad 94f1f1c266 feat: add GeoIP country lookup with embedded DB-IP Lite database (PLAN.md 4.3)
Embeds a DB-IP Lite country MMDB (~5MB) in the binary via go:embed,
keeping the single-binary deployment story clean. Country codes are
stored alongside login attempts and sessions, shown in the dashboard
(Top IPs, Top Countries card, Recent/Active Sessions, session detail).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:27:46 +01:00

70 lines
1.7 KiB
Go

package storage
import (
"context"
"log/slog"
"testing"
"time"
)
func TestRunRetentionDeletesOldRecords(t *testing.T) {
store := newTestStore(t)
ctx := context.Background()
logger := slog.Default()
// Insert an old login attempt (200 days ago).
oldTime := time.Now().AddDate(0, 0, -200).UTC().Format(time.RFC3339)
_, err := store.db.Exec(`
INSERT INTO login_attempts (username, password, ip, count, first_seen, last_seen)
VALUES ('old', 'old', '1.1.1.1', 1, ?, ?)`, oldTime, oldTime)
if err != nil {
t.Fatalf("insert old attempt: %v", err)
}
// Insert a recent login attempt.
if err := store.RecordLoginAttempt(ctx, "new", "new", "2.2.2.2", ""); err != nil {
t.Fatalf("insert recent attempt: %v", err)
}
// Run retention with a short interval. Cancel immediately after first run.
retentionCtx, cancel := context.WithCancel(ctx)
done := make(chan struct{})
go func() {
RunRetention(retentionCtx, store, 90, 24*time.Hour, logger)
close(done)
}()
// Give it a moment to run the initial prune.
time.Sleep(100 * time.Millisecond)
cancel()
<-done
// Verify old record was deleted.
var count int
store.db.QueryRow(`SELECT COUNT(*) FROM login_attempts`).Scan(&count)
if count != 1 {
t.Errorf("remaining attempts = %d, want 1", count)
}
}
func TestRunRetentionCancellation(t *testing.T) {
store := newTestStore(t)
logger := slog.Default()
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
go func() {
RunRetention(ctx, store, 90, time.Millisecond, logger)
close(done)
}()
// Cancel and verify it exits.
cancel()
select {
case <-done:
// OK
case <-time.After(5 * time.Second):
t.Fatal("RunRetention did not exit after cancel")
}
}