krz/gitbay

A CLI-first git forge.

clone: git clone https://gitbay.org/krz/gitbay.git

repo-descriptions: internal/store/store_test.go · raw

 1package store
 2
 3import (
 4	"path/filepath"
 5	"strings"
 6	"testing"
 7)
 8
 9func open(t *testing.T) *Store {
10	t.Helper()
11	s, err := Open(filepath.Join(t.TempDir(), "gitbay.db"))
12	if err != nil {
13		t.Fatal(err)
14	}
15	t.Cleanup(func() { s.Close() })
16	return s
17}
18
19func TestMigrateUpDown(t *testing.T) {
20	s := open(t)
21
22	if err := s.MigrateUp(); err != nil {
23		t.Fatal(err)
24	}
25	v, err := s.Version()
26	if err != nil {
27		t.Fatal(err)
28	}
29	if v < 1 {
30		t.Fatalf("version %d after MigrateUp", v)
31	}
32
33	// Seeded settings row exists.
34	var epoch string
35	if err := s.DB.QueryRow("SELECT value FROM settings WHERE key = 'key_epoch'").Scan(&epoch); err != nil {
36		t.Fatal(err)
37	}
38	if epoch != "1" {
39		t.Fatalf("key_epoch = %q, want 1", epoch)
40	}
41
42	// Down to empty, then back up.
43	if err := s.MigrateTo(0); err != nil {
44		t.Fatal(err)
45	}
46	var n int
47	if err := s.DB.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").Scan(&n); err != nil {
48		t.Fatal(err)
49	}
50	if n != 0 {
51		t.Fatalf("%d tables remain after down-migration to 0", n)
52	}
53	if err := s.MigrateUp(); err != nil {
54		t.Fatal(err)
55	}
56	// Idempotent at latest.
57	if err := s.MigrateUp(); err != nil {
58		t.Fatal(err)
59	}
60}
61
62func TestKeyFingerprintGloballyUnique(t *testing.T) {
63	s := open(t)
64	if err := s.MigrateUp(); err != nil {
65		t.Fatal(err)
66	}
67	mustExec := func(q string, args ...any) {
68		t.Helper()
69		if _, err := s.DB.Exec(q, args...); err != nil {
70			t.Fatal(err)
71		}
72	}
73	mustExec("INSERT INTO users (username) VALUES ('alice'), ('bob')")
74	mustExec("INSERT INTO ssh_keys (user_id, fingerprint, algo, blob) VALUES (1, 'SHA256:aaa', 'ed25519', x'00')")
75
76	// Same fingerprint on a different account must be rejected.
77	_, err := s.DB.Exec("INSERT INTO ssh_keys (user_id, fingerprint, algo, blob) VALUES (2, 'SHA256:aaa', 'ed25519', x'00')")
78	if err == nil || !strings.Contains(err.Error(), "UNIQUE") {
79		t.Fatalf("duplicate ssh fingerprint across accounts: err = %v, want UNIQUE violation", err)
80	}
81
82	mustExec("INSERT INTO pgp_keys (user_id, fingerprint, armored) VALUES (1, 'FPR1', '-----')")
83	_, err = s.DB.Exec("INSERT INTO pgp_keys (user_id, fingerprint, armored) VALUES (2, 'FPR1', '-----')")
84	if err == nil || !strings.Contains(err.Error(), "UNIQUE") {
85		t.Fatalf("duplicate pgp fingerprint across accounts: err = %v, want UNIQUE violation", err)
86	}
87}
88
89func TestForeignKeysEnforced(t *testing.T) {
90	s := open(t)
91	if err := s.MigrateUp(); err != nil {
92		t.Fatal(err)
93	}
94	_, err := s.DB.Exec("INSERT INTO ssh_keys (user_id, fingerprint, algo, blob) VALUES (999, 'SHA256:zzz', 'ed25519', x'00')")
95	if err == nil {
96		t.Fatal("insert with dangling user_id succeeded; foreign keys are off")
97	}
98}