database_test.go
⎇
Raw
1package database
2
3import (
4 "database/sql"
5 "path/filepath"
6 "testing"
7
8 "vidarchive/internal/config"
9)
10
11func newTestDB(t *testing.T) *sql.DB {
12 t.Helper()
13 db, err := New(&config.Config{DBPath: filepath.Join(t.TempDir(), "test.db")})
14 if err != nil {
15 t.Fatalf("New: %v", err)
16 }
17 t.Cleanup(func() { db.Close() })
18 return db
19}
20
21func TestMigrateIsIdempotent(t *testing.T) {
22 path := filepath.Join(t.TempDir(), "test.db")
23
24 db, err := New(&config.Config{DBPath: path})
25 if err != nil {
26 t.Fatalf("first migrate: %v", err)
27 }
28 var first int
29 if err := db.QueryRow(`SELECT MAX(version) FROM schema_migrations`).Scan(&first); err != nil {
30 t.Fatalf("read version: %v", err)
31 }
32 db.Close()
33
34 db, err = New(&config.Config{DBPath: path})
35 if err != nil {
36 t.Fatalf("second migrate: %v", err)
37 }
38 defer db.Close()
39
40 var second int
41 if err := db.QueryRow(`SELECT MAX(version) FROM schema_migrations`).Scan(&second); err != nil {
42 t.Fatalf("read version: %v", err)
43 }
44 if first != second {
45 t.Errorf("version changed on re-open: %d -> %d", first, second)
46 }
47}
48
49func TestForeignKeysAreEnforced(t *testing.T) {
50 db := newTestDB(t)
51
52 var on int
53 if err := db.QueryRow(`PRAGMA foreign_keys`).Scan(&on); err != nil {
54 t.Fatalf("read pragma: %v", err)
55 }
56 if on != 1 {
57 t.Fatal("foreign_keys pragma is off; declared constraints would be ignored")
58 }
59
60 if _, err := db.Exec(`INSERT INTO downloads (url, preset_id) VALUES ('u', 99999)`); err == nil {
61 t.Error("expected insert with a nonexistent preset_id to be rejected")
62 }
63}
64
65// Deleting a preset must not fail just because downloads reference it: the
66// reference is nulled and ExecuteDownload falls back to the default preset.
67func TestDeletingPresetNullsReferences(t *testing.T) {
68 db := newTestDB(t)
69
70 res, err := db.Exec(`INSERT INTO presets (name) VALUES ('temp')`)
71 if err != nil {
72 t.Fatalf("insert preset: %v", err)
73 }
74 presetID, err := res.LastInsertId()
75 if err != nil {
76 t.Fatal(err)
77 }
78
79 if _, err := db.Exec(`INSERT INTO downloads (url, preset_id) VALUES ('u', ?)`, presetID); err != nil {
80 t.Fatalf("insert download: %v", err)
81 }
82
83 if _, err := db.Exec(`DELETE FROM presets WHERE id = ?`, presetID); err != nil {
84 t.Fatalf("delete preset: %v", err)
85 }
86
87 var nulls int
88 if err := db.QueryRow(`SELECT COUNT(*) FROM downloads WHERE preset_id IS NULL`).Scan(&nulls); err != nil {
89 t.Fatal(err)
90 }
91 if nulls != 1 {
92 t.Errorf("preset_id not nulled after preset delete: got %d rows with NULL", nulls)
93 }
94}
95
96func TestExpectedIndexesExist(t *testing.T) {
97 db := newTestDB(t)
98
99 want := []string{
100 "idx_downloads_status",
101 "idx_downloads_subscription_id",
102 "idx_subscriptions_due",
103 }
104 for _, name := range want {
105 var got string
106 err := db.QueryRow(`SELECT name FROM sqlite_master WHERE type='index' AND name = ?`, name).Scan(&got)
107 if err != nil {
108 t.Errorf("missing index %s: %v", name, err)
109 }
110 }
111}
112