133 lines
4.4 KiB
Go
133 lines
4.4 KiB
Go
package sqlite_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.zaynet.fr/DoGaMa/DoGaMa-serv/internal/persistence/sqlite"
|
|
"git.zaynet.fr/DoGaMa/DoGaMa-serv/migrations"
|
|
)
|
|
|
|
func TestOpenAppliesMigrationsAndConfiguration(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "dogama.db")
|
|
db, err := sqlite.Open(context.Background(), path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
var count int
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM schema_migrations").Scan(&count); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if count != 6 {
|
|
t.Fatalf("got %d migrations, want 6", count)
|
|
}
|
|
for _, table := range []string{"instance_memberships", "permission_overrides", "installation_requests", "backup_policies", "backups", "imports"} {
|
|
var found int
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?", table).Scan(&found); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if found != 1 {
|
|
t.Fatalf("required table %q is missing", table)
|
|
}
|
|
}
|
|
var foreignKeys, busyTimeout int
|
|
var journalMode string
|
|
if err := db.QueryRow("PRAGMA foreign_keys").Scan(&foreignKeys); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.QueryRow("PRAGMA busy_timeout").Scan(&busyTimeout); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.QueryRow("PRAGMA journal_mode").Scan(&journalMode); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if foreignKeys != 1 || busyTimeout != 5000 || journalMode != "wal" {
|
|
t.Fatalf("unexpected pragmas: foreign_keys=%d busy_timeout=%d journal_mode=%s", foreignKeys, busyTimeout, journalMode)
|
|
}
|
|
|
|
if err := db.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
db, err = sqlite.Open(context.Background(), path)
|
|
if err != nil {
|
|
t.Fatalf("reopen migrated database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM schema_migrations").Scan(&count); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if count != 6 {
|
|
t.Fatalf("reopened database has %d migrations, want 6", count)
|
|
}
|
|
}
|
|
|
|
func TestLifecycleMigrationPreservesMilestoneThreeDrafts(t *testing.T) {
|
|
ctx := context.Background()
|
|
path := filepath.Join(t.TempDir(), "dogama.db")
|
|
db, err := sql.Open("sqlite", "file:"+path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := db.ExecContext(ctx, `CREATE TABLE schema_migrations (version TEXT PRIMARY KEY, applied_at TEXT NOT NULL)`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, name := range []string{"0001_initial.sql", "0002_catalog_instances.sql"} {
|
|
body, err := migrations.Files.ReadFile(name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tx, err := db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, statement := range strings.Split(string(body), ";") {
|
|
if strings.TrimSpace(statement) == "" {
|
|
continue
|
|
}
|
|
if _, err = tx.ExecContext(ctx, statement); err != nil {
|
|
_ = tx.Rollback()
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if _, err := tx.ExecContext(ctx, "INSERT INTO schema_migrations(version, applied_at) VALUES (?, ?)", name, time.Now().UTC().Format(time.RFC3339Nano)); err != nil {
|
|
_ = tx.Rollback()
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx.Commit(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
now := time.Now().UTC().Format(time.RFC3339Nano)
|
|
if _, err := db.ExecContext(ctx, `INSERT INTO templates(id, origin, trust_status, active_version, created_at, updated_at) VALUES ('template', 'official', 'official', '1.0.0', ?, ?)`, now, now); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := db.ExecContext(ctx, `INSERT INTO template_versions(template_id, version, schema_version, canonical_yaml, digest, game_id, game_name, description, created_at) VALUES ('template', '1.0.0', 1, '{}', ?, 'game', 'Game', 'Description', ?)`, strings.Repeat("a", 64), now); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := db.ExecContext(ctx, `INSERT INTO instances(id, slug, display_name, template_id, template_version, template_digest, revision, lifecycle_state, preview_json, plan_digest, created_at, updated_at) VALUES ('instance', 'instance', 'Instance', 'template', '1.0.0', ?, 1, 'draft', '{}', ?, ?, ?)`, strings.Repeat("a", 64), strings.Repeat("b", 64), now, now); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
db, err = sqlite.Open(ctx, path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
var lifecycle, observed string
|
|
if err := db.QueryRowContext(ctx, "SELECT lifecycle_state, observed_state FROM instances WHERE id='instance'").Scan(&lifecycle, &observed); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if lifecycle != "draft" || observed != "unknown" {
|
|
t.Fatalf("migrated lifecycle=%q observed=%q", lifecycle, observed)
|
|
}
|
|
}
|