Files
kindexr/internal/db/db_test.go
T
enki 1b7b70426c feat: Phase 0 bootstrap — kindexr boots, migrates, serves /health
- config: koanf-based loading (defaults → YAML → KINDEXR_ env vars)
- db: embedded SQLite migrations with BEGIN/END-aware statement splitter
- server: chi router, GET /health returns JSON stats
- cmd/kindexr: graceful SIGTERM shutdown
- cmd/kindexr-cli: stub
- deploy: systemd unit, example config, nginx snippet
- all packages covered by race-clean tests
2026-05-16 18:45:15 -07:00

123 lines
2.7 KiB
Go

package db_test
import (
"context"
"database/sql"
"path/filepath"
"testing"
"git.utn.lol/enki/kindexr/internal/db"
)
func tempDB(t *testing.T) *db.DB {
t.Helper()
dir := t.TempDir()
path := filepath.Join(dir, "test.db")
d, err := db.Open(path)
if err != nil {
t.Fatalf("Open failed: %v", err)
}
t.Cleanup(func() { d.Close() })
return d
}
func TestOpen(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "test.db")
d, err := db.Open(path)
if err != nil {
t.Fatalf("Open returned error: %v", err)
}
d.Close()
}
func TestMigrationsApplied(t *testing.T) {
d := tempDB(t)
ctx := context.Background()
version, err := d.MigrationVersion(ctx)
if err != nil {
t.Fatalf("MigrationVersion error: %v", err)
}
if version < 1 {
t.Errorf("expected at least 1 migration applied, got version %d", version)
}
}
func TestMigrationsIdempotent(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "test.db")
d1, err := db.Open(path)
if err != nil {
t.Fatalf("first Open failed: %v", err)
}
d1.Close()
d2, err := db.Open(path)
if err != nil {
t.Fatalf("second Open failed (idempotency): %v", err)
}
d2.Close()
}
func TestSchema(t *testing.T) {
d := tempDB(t)
expectedTables := []string{
"torrents", "files", "trackers", "tags",
"publishers", "relays", "api_keys", "health", "comments",
}
for _, table := range expectedTables {
var name string
err := d.QueryRow(
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table,
).Scan(&name)
if err == sql.ErrNoRows {
t.Errorf("expected table %q to exist, but it does not", table)
} else if err != nil {
t.Errorf("querying for table %q: %v", table, err)
}
}
}
func TestFTS5(t *testing.T) {
d := tempDB(t)
// Insert a torrent row.
_, err := d.Exec(`
INSERT INTO torrents
(event_id, info_hash, pubkey, created_at, ingested_at, title, description, raw_event)
VALUES
('evt1', 'aabbcc', 'pubkey1', 1715000000, 1715000001, 'test torrent title', 'test description', '{}')
`)
if err != nil {
t.Fatalf("insert torrent: %v", err)
}
// FTS5 search.
var rowid int64
err = d.QueryRow(`SELECT rowid FROM torrents_fts WHERE torrents_fts MATCH 'test'`).Scan(&rowid)
if err == sql.ErrNoRows {
t.Error("FTS5 search for 'test' returned no rows; trigger may not be working")
} else if err != nil {
t.Fatalf("FTS5 search error: %v", err)
}
}
func TestGetStats(t *testing.T) {
d := tempDB(t)
ctx := context.Background()
stats, err := d.GetStats(ctx)
if err != nil {
t.Fatalf("GetStats error: %v", err)
}
if stats.EventsTotal != 0 {
t.Errorf("expected EventsTotal=0, got %d", stats.EventsTotal)
}
if stats.LastEventAt != nil {
t.Errorf("expected LastEventAt=nil, got %v", stats.LastEventAt)
}
}