Add database package
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ExpectedUserVersion is the schema version after all migrations have been applied.
|
||||
// Increment this when adding a new migration file.
|
||||
const ExpectedUserVersion = 1
|
||||
|
||||
func TestSchema(t *testing.T) {
|
||||
var (
|
||||
ctx = t.Context()
|
||||
db = createDB(t)
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
t.Run("InitialVersion", func(t *testing.T) {
|
||||
testInitialVersion(t, ctx, db)
|
||||
})
|
||||
|
||||
if err := db.ApplySchema(ctx, nil); err != nil {
|
||||
t.Fatalf("ApplySchema: %v", err)
|
||||
}
|
||||
|
||||
t.Run("ApplySchema", func(t *testing.T) {
|
||||
testApplySchema(t, ctx, db)
|
||||
})
|
||||
t.Run("ApplySchemaIdempotent", func(t *testing.T) {
|
||||
testSchemaIdempotent(t, ctx, db)
|
||||
})
|
||||
t.Run("ApplySchemaTablesExist", func(t *testing.T) {
|
||||
testTablesExist(t, ctx, db)
|
||||
})
|
||||
t.Run("ApplySchemaIndexesExist", func(t *testing.T) {
|
||||
testSchemaIndexes(t, ctx, db)
|
||||
})
|
||||
}
|
||||
|
||||
func testInitialVersion(t *testing.T, ctx context.Context, db *SQLite) {
|
||||
var version int
|
||||
err := db.Reader.QueryRowContext(
|
||||
ctx,
|
||||
"PRAGMA user_version",
|
||||
).Scan(&version)
|
||||
if err != nil {
|
||||
t.Fatalf("PRAGMA user_version: %v", err)
|
||||
}
|
||||
if version != 0 {
|
||||
t.Fatalf("expected initial version 0, got %d", version)
|
||||
}
|
||||
}
|
||||
|
||||
func testApplySchema(t *testing.T, ctx context.Context, db *SQLite) {
|
||||
var version int
|
||||
err := db.Reader.QueryRowContext(
|
||||
ctx,
|
||||
"PRAGMA user_version",
|
||||
).Scan(&version)
|
||||
if err != nil {
|
||||
t.Fatalf("PRAGMA user_version: %v", err)
|
||||
}
|
||||
if version != ExpectedUserVersion {
|
||||
t.Fatalf("expected version %d, got %d", ExpectedUserVersion, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testTablesExist(t *testing.T, ctx context.Context, db *SQLite) {
|
||||
expected := []string{
|
||||
"approvals",
|
||||
"conversations",
|
||||
"messages",
|
||||
"sessions",
|
||||
"users",
|
||||
}
|
||||
for _, table := range expected {
|
||||
var exists bool
|
||||
err := db.Reader.QueryRowContext(
|
||||
ctx,
|
||||
"SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1)",
|
||||
table,
|
||||
).Scan(&exists)
|
||||
if err != nil {
|
||||
t.Fatalf("query sqlite_master for %s: %v", table, err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("table %s does not exist", table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSchemaIdempotent(t *testing.T, ctx context.Context, db *SQLite) {
|
||||
// Apply schema again; should succeed without error.
|
||||
if err := db.ApplySchema(ctx, nil); err != nil {
|
||||
t.Fatalf("second ApplySchema: %v", err)
|
||||
}
|
||||
|
||||
var version int
|
||||
err := db.Reader.QueryRowContext(
|
||||
ctx,
|
||||
"PRAGMA user_version",
|
||||
).Scan(&version)
|
||||
if err != nil {
|
||||
t.Fatalf("PRAGMA user_version: %v", err)
|
||||
}
|
||||
if version != ExpectedUserVersion {
|
||||
t.Fatalf("expected version %d, got %d", ExpectedUserVersion, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testSchemaIndexes(t *testing.T, ctx context.Context, db *SQLite) {
|
||||
expected := []string{
|
||||
"idx_approvals_message",
|
||||
"idx_approvals_pending",
|
||||
"idx_conv_user",
|
||||
"idx_msg_conv",
|
||||
"idx_msg_conv_seq",
|
||||
"idx_sessions_active",
|
||||
"idx_users_deactivated",
|
||||
}
|
||||
for _, idx := range expected {
|
||||
var exists bool
|
||||
err := db.Reader.QueryRowContext(
|
||||
ctx,
|
||||
"SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type = 'index' AND name = ? LIMIT 1)",
|
||||
idx,
|
||||
).Scan(&exists)
|
||||
if err != nil {
|
||||
t.Fatalf("query sqlite_master for index %s: %v", idx, err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("index %s does not exist", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user